From 82ad759143ed77673db0d93d53c1cde7b99917ee Mon Sep 17 00:00:00 2001 From: Philipp Puschmann Date: Wed, 27 Feb 2019 16:17:33 +0100 Subject: ASoC: tlv320aic3x: fix reset gpio reference counting This patch fixes a bug that prevents freeing the reset gpio on unloading the module. aic3x_i2c_probe is called when loading the module and it calls list_add with a probably uninitialized list entry aic3x->list (next = prev = NULL)). So even if list_del is called it does nothing and in the end the gpio_reset is not freed. Then a repeated module probing fails silently because gpio_request fails. When moving INIT_LIST_HEAD to aic3x_i2c_probe we also have to move list_del to aic3x_i2c_remove because aic3x_remove may be called multiple times without aic3x_i2c_remove being called which leads to a NULL pointer dereference. Signed-off-by: Philipp Puschmann Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic3x.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 6aa0edf8c5ef..cea3ebecdb12 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -1609,7 +1609,6 @@ static int aic3x_probe(struct snd_soc_component *component) struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component); int ret, i; - INIT_LIST_HEAD(&aic3x->list); aic3x->component = component; for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) { @@ -1692,7 +1691,6 @@ 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); @@ -1890,6 +1888,7 @@ static int aic3x_i2c_probe(struct i2c_client *i2c, if (ret != 0) goto err_gpio; + INIT_LIST_HEAD(&aic3x->list); list_add(&aic3x->list, &reset_list); return 0; @@ -1906,6 +1905,8 @@ static int aic3x_i2c_remove(struct i2c_client *client) { struct aic3x_priv *aic3x = i2c_get_clientdata(client); + list_del(&aic3x->list); + if (gpio_is_valid(aic3x->gpio_reset) && !aic3x_is_shared_reset(aic3x)) { gpio_set_value(aic3x->gpio_reset, 0); -- cgit v1.2.3-59-g8ed1b From f060f46f09bb920d1e0d436d654996033b856e26 Mon Sep 17 00:00:00 2001 From: KaiChieh Chuang Date: Wed, 27 Feb 2019 09:30:44 +0800 Subject: ASoC: mediatek: btcvsd add loopback add direct loopback path from rx to tx Signed-off-by: KaiChieh Chuang Signed-off-by: Mark Brown --- sound/soc/mediatek/common/mtk-btcvsd.c | 69 +++++++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/mediatek/common/mtk-btcvsd.c b/sound/soc/mediatek/common/mtk-btcvsd.c index 1b8bcdaf02d1..9a163d7064d1 100644 --- a/sound/soc/mediatek/common/mtk-btcvsd.c +++ b/sound/soc/mediatek/common/mtk-btcvsd.c @@ -49,6 +49,7 @@ enum bt_sco_state { BT_SCO_STATE_IDLE, BT_SCO_STATE_RUNNING, BT_SCO_STATE_ENDING, + BT_SCO_STATE_LOOPBACK, }; enum bt_sco_direct { @@ -486,7 +487,8 @@ static irqreturn_t mtk_btcvsd_snd_irq_handler(int irq_id, void *dev) 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) { + bt->tx->state != BT_SCO_STATE_ENDING && + bt->tx->state != BT_SCO_STATE_LOOPBACK) { 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; @@ -512,6 +514,42 @@ static irqreturn_t mtk_btcvsd_snd_irq_handler(int irq_id, void *dev) buf_cnt_tx = btsco_packet_info[packet_type][2]; buf_cnt_rx = btsco_packet_info[packet_type][3]; + if (bt->tx->state == BT_SCO_STATE_LOOPBACK) { + u8 *src, *dst; + unsigned long connsys_addr_rx, ap_addr_rx; + unsigned long connsys_addr_tx, ap_addr_tx; + + connsys_addr_rx = *bt->bt_reg_pkt_r; + ap_addr_rx = (unsigned long)bt->bt_sram_bank2_base + + (connsys_addr_rx & 0xFFFF); + + 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 || + connsys_addr_rx == 0xdeadfeed) { + /* bt return 0xdeadfeed if read reg during bt sleep */ + dev_warn(bt->dev, "%s(), connsys_addr_tx == 0xdeadfeed\n", + __func__); + goto irq_handler_exit; + } + + src = (u8 *)ap_addr_rx; + dst = (u8 *)ap_addr_tx; + + mtk_btcvsd_snd_data_transfer(BT_SCO_DIRECT_BT2ARM, src, + bt->tx->temp_packet_buf, + packet_length, + packet_num); + mtk_btcvsd_snd_data_transfer(BT_SCO_DIRECT_ARM2BT, + bt->tx->temp_packet_buf, dst, + packet_length, + packet_num); + bt->rx->rw_cnt++; + bt->tx->rw_cnt++; + } + if (bt->rx->state == BT_SCO_STATE_RUNNING || bt->rx->state == BT_SCO_STATE_ENDING) { if (bt->rx->xrun) { @@ -1067,6 +1105,33 @@ static int btcvsd_band_set(struct snd_kcontrol *kcontrol, return 0; } +static int btcvsd_loopback_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); + bool lpbk_en = bt->tx->state == BT_SCO_STATE_LOOPBACK; + + ucontrol->value.integer.value[0] = lpbk_en; + return 0; +} + +static int btcvsd_loopback_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 (ucontrol->value.integer.value[0]) { + mtk_btcvsd_snd_set_state(bt, bt->tx, BT_SCO_STATE_LOOPBACK); + mtk_btcvsd_snd_set_state(bt, bt->rx, BT_SCO_STATE_LOOPBACK); + } else { + mtk_btcvsd_snd_set_state(bt, bt->tx, BT_SCO_STATE_RUNNING); + mtk_btcvsd_snd_set_state(bt, bt->rx, BT_SCO_STATE_RUNNING); + } + return 0; +} + static int btcvsd_tx_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1202,6 +1267,8 @@ static int btcvsd_tx_timestamp_get(struct snd_kcontrol *kcontrol, 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 Loopback Switch", 0, + btcvsd_loopback_get, btcvsd_loopback_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, -- cgit v1.2.3-59-g8ed1b From 2e95f984aae4cf0608d0ba2189c756f2bd50b44a Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 28 Feb 2019 15:30:34 +0000 Subject: ASoC: hdmi-codec: fix S/PDIF DAI When using the S/PDIF DAI, there is no requirement to call snd_soc_dai_set_fmt() as there is no DAI format definition that defines S/PDIF. In any case, S/PDIF does not have separate clocks, this is embedded into the data stream. Consequently, when attempting to use TDA998x in S/PDIF mode, the attempt to configure TDA998x via the hw_params callback fails as the hdmi_codec_daifmt is left initialised to zero. Since the S/PDIF DAI will only be used by S/PDIF, prepare the hdmi_codec_daifmt structure for this format. Signed-off-by: Russell King Reviewed-by: Jyri Sarha Signed-off-by: Mark Brown --- sound/soc/codecs/hdmi-codec.c | 118 +++++++++++++++++++++--------------------- 1 file changed, 59 insertions(+), 59 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index e5b6769b9797..d5f73c837281 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -529,73 +529,71 @@ static int hdmi_codec_set_fmt(struct snd_soc_dai *dai, { struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); struct hdmi_codec_daifmt cf = { 0 }; - int ret = 0; dev_dbg(dai->dev, "%s()\n", __func__); - if (dai->id == DAI_ID_SPDIF) { - cf.fmt = HDMI_SPDIF; - } else { - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - cf.bit_clk_master = 1; - cf.frame_clk_master = 1; - break; - case SND_SOC_DAIFMT_CBS_CFM: - cf.frame_clk_master = 1; - break; - case SND_SOC_DAIFMT_CBM_CFS: - cf.bit_clk_master = 1; - break; - case SND_SOC_DAIFMT_CBS_CFS: - break; - default: - return -EINVAL; - } + if (dai->id == DAI_ID_SPDIF) + return 0; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + cf.bit_clk_master = 1; + cf.frame_clk_master = 1; + break; + case SND_SOC_DAIFMT_CBS_CFM: + cf.frame_clk_master = 1; + break; + case SND_SOC_DAIFMT_CBM_CFS: + cf.bit_clk_master = 1; + break; + case SND_SOC_DAIFMT_CBS_CFS: + break; + default: + return -EINVAL; + } - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_NB_NF: - break; - case SND_SOC_DAIFMT_NB_IF: - cf.frame_clk_inv = 1; - break; - case SND_SOC_DAIFMT_IB_NF: - cf.bit_clk_inv = 1; - break; - case SND_SOC_DAIFMT_IB_IF: - cf.frame_clk_inv = 1; - cf.bit_clk_inv = 1; - break; - } + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_NB_IF: + cf.frame_clk_inv = 1; + break; + case SND_SOC_DAIFMT_IB_NF: + cf.bit_clk_inv = 1; + break; + case SND_SOC_DAIFMT_IB_IF: + cf.frame_clk_inv = 1; + cf.bit_clk_inv = 1; + break; + } - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - cf.fmt = HDMI_I2S; - break; - case SND_SOC_DAIFMT_DSP_A: - cf.fmt = HDMI_DSP_A; - break; - case SND_SOC_DAIFMT_DSP_B: - cf.fmt = HDMI_DSP_B; - break; - case SND_SOC_DAIFMT_RIGHT_J: - cf.fmt = HDMI_RIGHT_J; - break; - case SND_SOC_DAIFMT_LEFT_J: - cf.fmt = HDMI_LEFT_J; - break; - case SND_SOC_DAIFMT_AC97: - cf.fmt = HDMI_AC97; - break; - default: - dev_err(dai->dev, "Invalid DAI interface format\n"); - return -EINVAL; - } + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + cf.fmt = HDMI_I2S; + break; + case SND_SOC_DAIFMT_DSP_A: + cf.fmt = HDMI_DSP_A; + break; + case SND_SOC_DAIFMT_DSP_B: + cf.fmt = HDMI_DSP_B; + break; + case SND_SOC_DAIFMT_RIGHT_J: + cf.fmt = HDMI_RIGHT_J; + break; + case SND_SOC_DAIFMT_LEFT_J: + cf.fmt = HDMI_LEFT_J; + break; + case SND_SOC_DAIFMT_AC97: + cf.fmt = HDMI_AC97; + break; + default: + dev_err(dai->dev, "Invalid DAI interface format\n"); + return -EINVAL; } hcp->daifmt[dai->id] = cf; - return ret; + return 0; } static int hdmi_codec_digital_mute(struct snd_soc_dai *dai, int mute) @@ -792,8 +790,10 @@ static int hdmi_codec_probe(struct platform_device *pdev) i++; } - if (hcd->spdif) + if (hcd->spdif) { hcp->daidrv[i] = hdmi_spdif_dai; + hcp->daifmt[DAI_ID_SPDIF].fmt = HDMI_SPDIF; + } dev_set_drvdata(dev, hcp); -- cgit v1.2.3-59-g8ed1b From 102cefc8e879b707be0024fdc7bce1deeb359a5f Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 1 Mar 2019 14:43:10 -0600 Subject: ASoC: ab8500: Mark expected switch fall-through MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In preparation to enabling -Wimplicit-fallthrough, mark switch cases where we are expecting to fall through. This patch fixes the following warning: In file included from sound/soc/codecs/ab8500-codec.c:24: sound/soc/codecs/ab8500-codec.c: In function ‘ab8500_codec_set_dai_fmt’: ./include/linux/device.h:1485:2: warning: this statement may fall through [-Wimplicit-fallthrough=] _dev_err(dev, dev_fmt(fmt), ##__VA_ARGS__) ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ sound/soc/codecs/ab8500-codec.c:2129:3: note: in expansion of macro ‘dev_err’ dev_err(dai->component->dev, ^~~~~~~ sound/soc/codecs/ab8500-codec.c:2132:2: note: here default: ^~~~~~~ Warning level 3 was used: -Wimplicit-fallthrough=3 This patch is part of the ongoing efforts to enable -Wimplicit-fallthrough. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Mark Brown --- sound/soc/codecs/ab8500-codec.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/soc') diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index 03bbbcd3b6c1..87616b126018 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c @@ -2129,6 +2129,7 @@ static int ab8500_codec_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) dev_err(dai->component->dev, "%s: ERROR: The device is either a master or a slave.\n", __func__); + /* fall through */ default: dev_err(dai->component->dev, "%s: ERROR: Unsupporter master mask 0x%x\n", -- cgit v1.2.3-59-g8ed1b From 5f8a1000c3e630c3ac06f1d664eeaa755bce8823 Mon Sep 17 00:00:00 2001 From: Olivier Moysan Date: Thu, 28 Feb 2019 14:19:21 +0100 Subject: ASoC: stm32: sai: fix iec958 controls indexation Allow indexation of sai iec958 controls according to device id. Signed-off-by: Olivier Moysan Signed-off-by: Mark Brown --- sound/soc/stm/stm32_sai_sub.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index f9297228c41c..506360b7bc01 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -100,7 +100,7 @@ * @slot_mask: rx or tx active slots mask. set at init or at runtime * @data_size: PCM data width. corresponds to PCM substream width. * @spdif_frm_cnt: S/PDIF playback frame counter - * @snd_aes_iec958: iec958 data + * @iec958: iec958 data * @ctrl_lock: control lock */ struct stm32_sai_sub_data { @@ -1068,11 +1068,12 @@ static int stm32_sai_pcm_new(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *cpu_dai) { struct stm32_sai_sub_data *sai = dev_get_drvdata(cpu_dai->dev); + struct snd_kcontrol_new knew = iec958_ctls; if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) { dev_dbg(&sai->pdev->dev, "%s: register iec controls", __func__); - return snd_ctl_add(rtd->pcm->card, - snd_ctl_new1(&iec958_ctls, sai)); + knew.device = rtd->pcm->device; + return snd_ctl_add(rtd->pcm->card, snd_ctl_new1(&knew, sai)); } return 0; -- cgit v1.2.3-59-g8ed1b From b8468192971807c43a80d6e2c41f83141cb7b211 Mon Sep 17 00:00:00 2001 From: Olivier Moysan Date: Thu, 28 Feb 2019 14:19:22 +0100 Subject: ASoC: stm32: sai: fix exposed capabilities in spdif mode Change capabilities exposed in SAI S/PDIF mode, to match actually supported formats. In S/PDIF mode only 32 bits stereo is supported. Signed-off-by: Olivier Moysan Signed-off-by: Mark Brown --- sound/soc/stm/stm32_sai_sub.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index 506360b7bc01..e418f446e03b 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -682,6 +682,14 @@ static int stm32_sai_startup(struct snd_pcm_substream *substream, sai->substream = substream; + if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) { + snd_pcm_hw_constraint_mask64(substream->runtime, + SNDRV_PCM_HW_PARAM_FORMAT, + SNDRV_PCM_FMTBIT_S32_LE); + snd_pcm_hw_constraint_single(substream->runtime, + SNDRV_PCM_HW_PARAM_CHANNELS, 2); + } + ret = clk_prepare_enable(sai->sai_ck); if (ret < 0) { dev_err(cpu_dai->dev, "Failed to enable clock: %d\n", ret); -- cgit v1.2.3-59-g8ed1b From 26f98e82dd49b7c3cc5ef0edd882aa732a62b672 Mon Sep 17 00:00:00 2001 From: Olivier Moysan Date: Thu, 28 Feb 2019 14:19:23 +0100 Subject: ASoC: stm32: sai: 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_sai_sub.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index e418f446e03b..cad415e03b5e 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -102,6 +102,7 @@ * @spdif_frm_cnt: S/PDIF playback frame counter * @iec958: iec958 data * @ctrl_lock: control lock + * @irq_lock: prevent race condition with IRQ */ struct stm32_sai_sub_data { struct platform_device *pdev; @@ -133,6 +134,7 @@ struct stm32_sai_sub_data { unsigned int spdif_frm_cnt; struct snd_aes_iec958 iec958; struct mutex ctrl_lock; /* protect resources accessed by controls */ + spinlock_t irq_lock; /* used to prevent race condition with IRQ */ }; enum stm32_sai_fifo_th { @@ -474,8 +476,10 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid) status = SNDRV_PCM_STATE_XRUN; } - if (status != SNDRV_PCM_STATE_RUNNING) + spin_lock(&sai->irq_lock); + if (status != SNDRV_PCM_STATE_RUNNING && sai->substream) snd_pcm_stop_xrun(sai->substream); + spin_unlock(&sai->irq_lock); return IRQ_HANDLED; } @@ -679,8 +683,11 @@ static int stm32_sai_startup(struct snd_pcm_substream *substream, { struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai); int imr, cr2, ret; + unsigned long flags; + spin_lock_irqsave(&sai->irq_lock, flags); sai->substream = substream; + spin_unlock_irqrestore(&sai->irq_lock, flags); if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) { snd_pcm_hw_constraint_mask64(substream->runtime, @@ -1059,6 +1066,7 @@ static void stm32_sai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai); + unsigned long flags; regmap_update_bits(sai->regmap, STM_SAI_IMR_REGX, SAI_XIMR_MASK, 0); @@ -1069,7 +1077,9 @@ static void stm32_sai_shutdown(struct snd_pcm_substream *substream, clk_rate_exclusive_put(sai->sai_mclk); + spin_lock_irqsave(&sai->irq_lock, flags); sai->substream = NULL; + spin_unlock_irqrestore(&sai->irq_lock, flags); } static int stm32_sai_pcm_new(struct snd_soc_pcm_runtime *rtd, @@ -1433,6 +1443,7 @@ static int stm32_sai_sub_probe(struct platform_device *pdev) sai->pdev = pdev; mutex_init(&sai->ctrl_lock); + spin_lock_init(&sai->irq_lock); platform_set_drvdata(pdev, sai); sai->pdata = dev_get_drvdata(pdev->dev.parent); -- cgit v1.2.3-59-g8ed1b From 71d9537fada47762a1a1b33a8a1f95a92d7edc11 Mon Sep 17 00:00:00 2001 From: Olivier Moysan Date: Thu, 28 Feb 2019 14:19:24 +0100 Subject: ASoC: stm32: sai: fix oversampling mode Set OSR bit if mclk/fs ratio is 512. Signed-off-by: Olivier Moysan Signed-off-by: Mark Brown --- sound/soc/stm/stm32_sai_sub.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index cad415e03b5e..cb658463ccd1 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -913,7 +913,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 div = 0; + int div = 0, cr1 = 0; int sai_clk_rate, mclk_ratio, den; unsigned int rate = params_rate(params); @@ -958,13 +958,19 @@ 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) && - (mclk_ratio != 256)) { + if (mclk_ratio == 512) { + cr1 = SAI_XCR1_OSR; + } else if (mclk_ratio != 256) { dev_err(cpu_dai->dev, "Wrong mclk ratio %d\n", mclk_ratio); return -EINVAL; } + + regmap_update_bits(sai->regmap, + STM_SAI_CR1_REGX, + SAI_XCR1_OSR, cr1); + div = stm32_sai_get_clk_div(sai, sai_clk_rate, sai->mclk_rate); if (div < 0) -- cgit v1.2.3-59-g8ed1b From d4180b4c02e7b04b8479f6237b2bd98b4c5fd19c Mon Sep 17 00:00:00 2001 From: Olivier Moysan Date: Thu, 28 Feb 2019 14:19:25 +0100 Subject: ASoC: stm32: sai: fix set_sync service Add error check on set_sync function return. Add of_node_put() as of_get_parent() takes a reference which has to be released. Signed-off-by: Olivier Moysan Signed-off-by: Mark Brown --- sound/soc/stm/stm32_sai.c | 8 +++++--- sound/soc/stm/stm32_sai_sub.c | 8 +++++--- 2 files changed, 10 insertions(+), 6 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c index 14c9591aae42..d68d62f12df5 100644 --- a/sound/soc/stm/stm32_sai.c +++ b/sound/soc/stm/stm32_sai.c @@ -105,6 +105,7 @@ static int stm32_sai_set_sync(struct stm32_sai_data *sai_client, if (!pdev) { dev_err(&sai_client->pdev->dev, "Device not found for node %pOFn\n", np_provider); + of_node_put(np_provider); return -ENODEV; } @@ -113,19 +114,20 @@ static int stm32_sai_set_sync(struct stm32_sai_data *sai_client, dev_err(&sai_client->pdev->dev, "SAI sync provider data not found\n"); ret = -EINVAL; - goto out_put_dev; + goto error; } /* Configure sync client */ ret = stm32_sai_sync_conf_client(sai_client, synci); if (ret < 0) - goto out_put_dev; + goto error; /* Configure sync provider */ ret = stm32_sai_sync_conf_provider(sai_provider, synco); -out_put_dev: +error: put_device(&pdev->dev); + of_node_put(np_provider); return ret; } diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index cb658463ccd1..55d802f51c15 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -1106,7 +1106,7 @@ static int stm32_sai_pcm_new(struct snd_soc_pcm_runtime *rtd, static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai) { struct stm32_sai_sub_data *sai = dev_get_drvdata(cpu_dai->dev); - int cr1 = 0, cr1_mask; + int cr1 = 0, cr1_mask, ret; sai->cpu_dai = cpu_dai; @@ -1136,8 +1136,10 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai) /* Configure synchronization */ if (sai->sync == SAI_SYNC_EXTERNAL) { /* Configure synchro client and provider */ - sai->pdata->set_sync(sai->pdata, sai->np_sync_provider, - sai->synco, sai->synci); + ret = sai->pdata->set_sync(sai->pdata, sai->np_sync_provider, + sai->synco, sai->synci); + if (ret) + return ret; } cr1_mask |= SAI_XCR1_SYNCEN_MASK; -- cgit v1.2.3-59-g8ed1b From bbf62563d8622434c761cb96569c132467f88597 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 28 Feb 2019 15:30:40 +0000 Subject: ASoC: hdmi-codec: avoid limiting params->msbits in hw_params() Limiting the value of the passed in params->msbits in the hw_params() callback is redundant on three counts: 1. We already specify in the DAI driver that we can only handle up to 24 bits. This means msbits will be limited to 24 via the ALSA constraints imposed by the ASoC core, unless we have multiple codecs that can handle more bits. 2. Nothing in our hw_params() implementation uses this value. 3. The copy of the params that we are passed by the ASoC core never reads back the msbits value. Consequently, this code is unnecessary and does nothing useful. Remove it. Signed-off-by: Russell King Reviewed-by: Jyri Sarha Signed-off-by: Mark Brown --- sound/soc/codecs/hdmi-codec.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index d5f73c837281..35df73e42cbc 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -484,9 +484,6 @@ static int hdmi_codec_hw_params(struct snd_pcm_substream *substream, params_width(params), params_rate(params), params_channels(params)); - if (params_width(params) > 24) - params->msbits = 24; - ret = snd_pcm_create_iec958_consumer_hw_params(params, hp.iec.status, sizeof(hp.iec.status)); if (ret < 0) { -- cgit v1.2.3-59-g8ed1b From c342febcde452f817cbd3896dc40953ab17c309d Mon Sep 17 00:00:00 2001 From: Jonathan Hunter Date: Mon, 4 Mar 2019 13:31:14 +0000 Subject: ASoC: soc-core: Fix probe deferral following prelink failure Commit 78a24e10cd94 ("ASoC: soc-core: clear platform pointers on error") re-worked the clean-up of any platform pointers that may have been initialised by the function snd_soc_init_platform(). This commit missed one error path where if any of the prelinks for a soundcard failed to initialise, then these platform pointers would not be cleaned-up. This then prevents the soundcard from being initialised following a probe deferral when any of the soundcard prelinks cannot be found. Fix this by ensuring that soc_cleanup_platform() is called when initialising the soundcard prelinks fails. Fixes: 78a24e10cd94 ("ASoC: soc-core: clear platform pointers on error") Signed-off-by: Jonathan Hunter Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/soc') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 93d316d5bf8e..5a5764dba147 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2797,6 +2797,7 @@ int snd_soc_register_card(struct snd_soc_card *card) ret = soc_init_dai_link(card, link); if (ret) { + soc_cleanup_platform(card); dev_err(card->dev, "ASoC: failed to init link %s\n", link->name); mutex_unlock(&client_mutex); -- cgit v1.2.3-59-g8ed1b From 42e4cedd67e4eb2abaa5e684353a55d4a01a913e Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 6 Mar 2019 11:24:45 +0100 Subject: ASoC: samsung: i2s: Fix DAPM routes for capture stream This patch sets missing stream_name of capture part of the DAI driver so we can define DAPM routing properly also for the capture stream. While at it "Playback" suffix is added to the playback stream names to clearly identify playback/capture. Together with related dts patch this fixes NULL pointer dereference when opening ALSA device for recording on Odroid XU3. Fixes: 64aba9bca5bd ("ASoC: samsung: i2s: Add widgets and routes for DPCM support") Signed-off-by: Sylwester Nawrocki Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 4231001226f4..ab471d550d17 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -1130,11 +1130,11 @@ static const struct snd_soc_dapm_widget samsung_i2s_widgets[] = { }; static const struct snd_soc_dapm_route samsung_i2s_dapm_routes[] = { - { "Playback Mixer", NULL, "Primary" }, - { "Playback Mixer", NULL, "Secondary" }, + { "Playback Mixer", NULL, "Primary Playback" }, + { "Playback Mixer", NULL, "Secondary Playback" }, { "Mixer DAI TX", NULL, "Playback Mixer" }, - { "Playback Mixer", NULL, "Mixer DAI RX" }, + { "Primary Capture", NULL, "Mixer DAI RX" }, }; static const struct snd_soc_component_driver samsung_i2s_component = { @@ -1155,7 +1155,8 @@ 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" }; + static const char *stream_names[] = { "Primary Playback", + "Secondary Playback" }; struct snd_soc_dai_driver *dai_drv; struct i2s_dai *dai; int i; @@ -1201,6 +1202,7 @@ static int i2s_alloc_dais(struct samsung_i2s_priv *priv, dai_drv->capture.channels_max = 2; dai_drv->capture.rates = i2s_dai_data->pcm_rates; dai_drv->capture.formats = SAMSUNG_I2S_FMTS; + dai_drv->capture.stream_name = "Primary Capture"; return 0; } -- cgit v1.2.3-59-g8ed1b From 570f18b6a8d1f0e60e8caf30e66161b6438dcc91 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Fri, 8 Mar 2019 16:38:57 +0800 Subject: ASoC:soc-pcm:fix a codec fixup issue in TDM case On HDaudio platforms, if playback is started when capture is working, there is no audible output. This can be root-caused to the use of the rx|tx_mask to store an HDaudio stream tag. If capture is stared before playback, rx_mask would be non-zero on HDaudio platform, then the channel number of playback, which is in the same codec dai with the capture, would be changed by soc_pcm_codec_params_fixup based on the tx_mask at first, then overwritten by this function based on rx_mask at last. According to the author of tx|rx_mask, tx_mask is for playback and rx_mask is for capture. And stream direction is checked at all other references of tx|rx_mask in ASoC, so here should be an error. This patch checks stream direction for tx|rx_mask for fixup function. This issue would affect not only HDaudio+ASoC, but also I2S codecs if the channel number based on rx_mask is not equal to the one for tx_mask. It could be rarely reproduecd because most drivers in kernel set the same channel number to tx|rx_mask or rx_mask is zero. Tested on all platforms using stream_tag & HDaudio and intel I2S platforms. Signed-off-by: Rander Wang Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index a5b40e82dea4..e70555a4ea06 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -954,10 +954,13 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, codec_params = *params; /* fixup params based on TDM slot masks */ - if (codec_dai->tx_mask) + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && + codec_dai->tx_mask) soc_pcm_codec_params_fixup(&codec_params, codec_dai->tx_mask); - if (codec_dai->rx_mask) + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE && + codec_dai->rx_mask) soc_pcm_codec_params_fixup(&codec_params, codec_dai->rx_mask); -- cgit v1.2.3-59-g8ed1b From 03d0aa4d4fddce4a5d865d819a4d98bfc3d451e6 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Fri, 8 Mar 2019 16:38:58 +0800 Subject: ASoC:hdac_hda:use correct format to setup hda codec The current implementation of the hdac_hda codec results in zero-valued samples on capture and noise with headset playback when SOF is used on platforms with an on-board HDaudio codec. This is root-caused to SOF using be_hw_params_fixup, and the prepare() call using invalid runtime fields to determine the format. This patch moves the format handling to the hw_params() callback, as done already for hdac_hdmi, to make sure the fixed-up information is taken into account but keeps the codec initialization in prepare() as the stream_tag is only available at that time. Moving everything in the prepare() callback is possible but the code is less elegant so this two-step solution was chosen. The solution was tested with the SST driver with no regressions, and all the issues with SOF playback and capture are solved. Signed-off-by: Rander Wang Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/hdac_hda.c | 53 +++++++++++++++++++++++++++++++++------------ sound/soc/codecs/hdac_hda.h | 1 + 2 files changed, 40 insertions(+), 14 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c index ffecdaaa8cf2..f889d94c8e3c 100644 --- a/sound/soc/codecs/hdac_hda.c +++ b/sound/soc/codecs/hdac_hda.c @@ -38,6 +38,9 @@ static void hdac_hda_dai_close(struct snd_pcm_substream *substream, struct snd_soc_dai *dai); static int hdac_hda_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai); +static int hdac_hda_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai); static int hdac_hda_dai_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai); static int hdac_hda_dai_set_tdm_slot(struct snd_soc_dai *dai, @@ -50,6 +53,7 @@ static const struct snd_soc_dai_ops hdac_hda_dai_ops = { .startup = hdac_hda_dai_open, .shutdown = hdac_hda_dai_close, .prepare = hdac_hda_dai_prepare, + .hw_params = hdac_hda_dai_hw_params, .hw_free = hdac_hda_dai_hw_free, .set_tdm_slot = hdac_hda_dai_set_tdm_slot, }; @@ -139,6 +143,39 @@ static int hdac_hda_dai_set_tdm_slot(struct snd_soc_dai *dai, return 0; } +static int hdac_hda_dai_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 hdac_hda_priv *hda_pvt; + unsigned int format_val; + unsigned int maxbps; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + maxbps = dai->driver->playback.sig_bits; + else + maxbps = dai->driver->capture.sig_bits; + + hda_pvt = snd_soc_component_get_drvdata(component); + format_val = snd_hdac_calc_stream_format(params_rate(params), + params_channels(params), + params_format(params), + maxbps, + 0); + if (!format_val) { + dev_err(dai->dev, + "invalid format_val, rate=%d, ch=%d, format=%d, maxbps=%d\n", + params_rate(params), params_channels(params), + params_format(params), maxbps); + + return -EINVAL; + } + + hda_pvt->pcm[dai->id].format_val[substream->stream] = format_val; + return 0; +} + static int hdac_hda_dai_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -162,10 +199,9 @@ static int hdac_hda_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_component *component = dai->component; + struct hda_pcm_stream *hda_stream; struct hdac_hda_priv *hda_pvt; - struct snd_pcm_runtime *runtime = substream->runtime; struct hdac_device *hdev; - struct hda_pcm_stream *hda_stream; unsigned int format_val; struct hda_pcm *pcm; unsigned int stream; @@ -179,19 +215,8 @@ static int hdac_hda_dai_prepare(struct snd_pcm_substream *substream, hda_stream = &pcm->stream[substream->stream]; - format_val = snd_hdac_calc_stream_format(runtime->rate, - runtime->channels, - runtime->format, - hda_stream->maxbps, - 0); - if (!format_val) { - dev_err(&hdev->dev, - "invalid format_val, rate=%d, ch=%d, format=%d\n", - runtime->rate, runtime->channels, runtime->format); - return -EINVAL; - } - stream = hda_pvt->pcm[dai->id].stream_tag[substream->stream]; + format_val = hda_pvt->pcm[dai->id].format_val[substream->stream]; ret = snd_hda_codec_prepare(&hda_pvt->codec, hda_stream, stream, format_val, substream); diff --git a/sound/soc/codecs/hdac_hda.h b/sound/soc/codecs/hdac_hda.h index e444ef593360..6b1bd4f428e7 100644 --- a/sound/soc/codecs/hdac_hda.h +++ b/sound/soc/codecs/hdac_hda.h @@ -8,6 +8,7 @@ struct hdac_hda_pcm { int stream_tag[2]; + unsigned int format_val[2]; }; struct hdac_hda_priv { -- cgit v1.2.3-59-g8ed1b From c899df3e9b0bf7b76e642aed1a214582ea7012d5 Mon Sep 17 00:00:00 2001 From: Rander Wang Date: Fri, 8 Mar 2019 16:38:59 +0800 Subject: ASoC:intel:skl:fix a simultaneous playback & capture issue on hda platform If playback and capture are enabled concurrently, when the capture stops the output becomes inaudile. The playback application will become stuck and underrun after a timeout. This is caused by mistaken use of the stream_id, which should only be set for playback and not for capture Tested on Apollolake and Kabylake with SST driver. Signed-off-by: Rander Wang Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-pcm.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index a4284778f117..bb463ee6ff84 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -181,6 +181,7 @@ int skl_pcm_link_dma_prepare(struct device *dev, struct skl_pipe_params *params) struct hdac_stream *hstream; struct hdac_ext_stream *stream; struct hdac_ext_link *link; + unsigned char stream_tag; hstream = snd_hdac_get_stream(bus, params->stream, params->link_dma_id + 1); @@ -199,10 +200,13 @@ int skl_pcm_link_dma_prepare(struct device *dev, struct skl_pipe_params *params) snd_hdac_ext_link_stream_setup(stream, format_val); - list_for_each_entry(link, &bus->hlink_list, list) { - if (link->index == params->link_index) - snd_hdac_ext_link_set_stream_id(link, - hstream->stream_tag); + stream_tag = hstream->stream_tag; + if (stream->hstream.direction == SNDRV_PCM_STREAM_PLAYBACK) { + list_for_each_entry(link, &bus->hlink_list, list) { + if (link->index == params->link_index) + snd_hdac_ext_link_set_stream_id(link, + stream_tag); + } } stream->link_prepared = 1; @@ -645,6 +649,7 @@ static int skl_link_hw_free(struct snd_pcm_substream *substream, struct hdac_ext_stream *link_dev = snd_soc_dai_get_dma_data(dai, substream); struct hdac_ext_link *link; + unsigned char stream_tag; dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); @@ -654,7 +659,11 @@ static int skl_link_hw_free(struct snd_pcm_substream *substream, if (!link) return -EINVAL; - snd_hdac_ext_link_clear_stream_id(link, hdac_stream(link_dev)->stream_tag); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + stream_tag = hdac_stream(link_dev)->stream_tag; + snd_hdac_ext_link_clear_stream_id(link, stream_tag); + } + snd_hdac_ext_stream_release(link_dev, HDAC_EXT_STREAM_TYPE_LINK); return 0; } -- cgit v1.2.3-59-g8ed1b From a9764869779081e8bf24da07ac040e8f3efcf13a Mon Sep 17 00:00:00 2001 From: KaiChieh Chuang Date: Fri, 8 Mar 2019 13:05:53 +0800 Subject: ASoC: dpcm: prevent snd_soc_dpcm use after free The dpcm get from fe_clients/be_clients may be free before use Add a spin lock at snd_soc_card level, to protect the dpcm instance. The lock may be used in atomic context, so use spin lock. Use irq spin lock version, since the lock may be used in interrupts. possible race condition between void dpcm_be_disconnect( ... list_del(&dpcm->list_be); list_del(&dpcm->list_fe); kfree(dpcm); ... and for_each_dpcm_fe() for_each_dpcm_be*() race condition example Thread 1: snd_soc_dapm_mixer_update_power() -> soc_dpcm_runtime_update() -> dpcm_be_disconnect() -> kfree(dpcm); Thread 2: dpcm_fe_dai_trigger() -> dpcm_be_dai_trigger() -> snd_soc_dpcm_can_be_free_stop() -> if (dpcm->fe == fe) Excpetion Scenario: two FE link to same BE FE1 -> BE FE2 -> Thread 1: switch of mixer between FE2 -> BE Thread 2: pcm_stop FE1 Exception: Unable to handle kernel paging request at virtual address dead0000000000e0 pc=<> [] dpcm_be_dai_trigger+0x29c/0x47c sound/soc/soc-pcm.c:3226 if (dpcm->fe == fe) lr=<> [] dpcm_fe_dai_do_trigger+0x94/0x26c Backtrace: [] notify_die+0x68/0xb8 [] die+0x118/0x2a8 [] __do_kernel_fault+0x13c/0x14c [] do_translation_fault+0x64/0xa0 [] do_mem_abort+0x4c/0xd0 [] el1_da+0x24/0x40 [] dpcm_be_dai_trigger+0x29c/0x47c [] dpcm_fe_dai_do_trigger+0x94/0x26c [] dpcm_fe_dai_trigger+0x3c/0x44 [] snd_pcm_do_stop+0x50/0x5c [] snd_pcm_action+0xb4/0x13c [] snd_pcm_drop+0xa0/0x128 [] snd_pcm_common_ioctl+0x9d8/0x30f0 [] snd_pcm_ioctl_compat+0x29c/0x2f14 [] compat_SyS_ioctl+0x128/0x244 [] el0_svc_naked+0x34/0x38 [] 0xffffffffffffffff Signed-off-by: KaiChieh Chuang Signed-off-by: Mark Brown --- include/sound/soc.h | 2 ++ sound/soc/soc-core.c | 1 + sound/soc/soc-pcm.c | 40 +++++++++++++++++++++++++++++++++------- 3 files changed, 36 insertions(+), 7 deletions(-) (limited to 'sound/soc') diff --git a/include/sound/soc.h b/include/sound/soc.h index eb7db605955b..1e2be35ed36f 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1083,6 +1083,8 @@ struct snd_soc_card { struct mutex mutex; struct mutex dapm_mutex; + spinlock_t dpcm_lock; + bool instantiated; bool topology_shortname_created; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 5a5764dba147..d88757659729 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2820,6 +2820,7 @@ int snd_soc_register_card(struct snd_soc_card *card) card->instantiated = 0; mutex_init(&card->mutex); mutex_init(&card->dapm_mutex); + spin_lock_init(&card->dpcm_lock); return snd_soc_bind_card(card); } diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index e70555a4ea06..90504c149931 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1216,6 +1216,7 @@ static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe, struct snd_soc_pcm_runtime *be, int stream) { struct snd_soc_dpcm *dpcm; + unsigned long flags; /* only add new dpcms */ for_each_dpcm_be(fe, stream, dpcm) { @@ -1231,8 +1232,10 @@ static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe, dpcm->fe = fe; be->dpcm[stream].runtime = fe->dpcm[stream].runtime; dpcm->state = SND_SOC_DPCM_LINK_STATE_NEW; + spin_lock_irqsave(&fe->card->dpcm_lock, flags); list_add(&dpcm->list_be, &fe->dpcm[stream].be_clients); list_add(&dpcm->list_fe, &be->dpcm[stream].fe_clients); + spin_unlock_irqrestore(&fe->card->dpcm_lock, flags); dev_dbg(fe->dev, "connected new DPCM %s path %s %s %s\n", stream ? "capture" : "playback", fe->dai_link->name, @@ -1278,6 +1281,7 @@ static void dpcm_be_reparent(struct snd_soc_pcm_runtime *fe, void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream) { struct snd_soc_dpcm *dpcm, *d; + unsigned long flags; for_each_dpcm_be_safe(fe, stream, dpcm, d) { dev_dbg(fe->dev, "ASoC: BE %s disconnect check for %s\n", @@ -1297,8 +1301,10 @@ void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream) #ifdef CONFIG_DEBUG_FS debugfs_remove(dpcm->debugfs_state); #endif + spin_lock_irqsave(&fe->card->dpcm_lock, flags); list_del(&dpcm->list_be); list_del(&dpcm->list_fe); + spin_unlock_irqrestore(&fe->card->dpcm_lock, flags); kfree(dpcm); } } @@ -1550,10 +1556,13 @@ int dpcm_process_paths(struct snd_soc_pcm_runtime *fe, void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream) { struct snd_soc_dpcm *dpcm; + unsigned long flags; + spin_lock_irqsave(&fe->card->dpcm_lock, flags); for_each_dpcm_be(fe, stream, dpcm) dpcm->be->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; + spin_unlock_irqrestore(&fe->card->dpcm_lock, flags); } static void dpcm_be_dai_startup_unwind(struct snd_soc_pcm_runtime *fe, @@ -2574,6 +2583,7 @@ static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream) struct snd_soc_dpcm *dpcm; enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream]; int ret; + unsigned long flags; dev_dbg(fe->dev, "ASoC: runtime %s open on FE %s\n", stream ? "capture" : "playback", fe->dai_link->name); @@ -2643,11 +2653,13 @@ close: dpcm_be_dai_shutdown(fe, stream); disconnect: /* disconnect any non started BEs */ + spin_lock_irqsave(&fe->card->dpcm_lock, flags); for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START) dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; } + spin_unlock_irqrestore(&fe->card->dpcm_lock, flags); return ret; } @@ -3223,7 +3235,10 @@ int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe, { struct snd_soc_dpcm *dpcm; int state; + int ret = 1; + unsigned long flags; + spin_lock_irqsave(&fe->card->dpcm_lock, flags); for_each_dpcm_fe(be, stream, dpcm) { if (dpcm->fe == fe) @@ -3232,12 +3247,15 @@ int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe, state = dpcm->fe->dpcm[stream].state; if (state == SND_SOC_DPCM_STATE_START || state == SND_SOC_DPCM_STATE_PAUSED || - state == SND_SOC_DPCM_STATE_SUSPEND) - return 0; + state == SND_SOC_DPCM_STATE_SUSPEND) { + ret = 0; + break; + } } + spin_unlock_irqrestore(&fe->card->dpcm_lock, flags); /* it's safe to free/stop this BE DAI */ - return 1; + return ret; } EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_free_stop); @@ -3250,7 +3268,10 @@ int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe, { struct snd_soc_dpcm *dpcm; int state; + int ret = 1; + unsigned long flags; + spin_lock_irqsave(&fe->card->dpcm_lock, flags); for_each_dpcm_fe(be, stream, dpcm) { if (dpcm->fe == fe) @@ -3260,12 +3281,15 @@ int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe, if (state == SND_SOC_DPCM_STATE_START || state == SND_SOC_DPCM_STATE_PAUSED || state == SND_SOC_DPCM_STATE_SUSPEND || - state == SND_SOC_DPCM_STATE_PREPARE) - return 0; + state == SND_SOC_DPCM_STATE_PREPARE) { + ret = 0; + break; + } } + spin_unlock_irqrestore(&fe->card->dpcm_lock, flags); /* it's safe to change hw_params */ - return 1; + return ret; } EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_params); @@ -3304,6 +3328,7 @@ static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe, struct snd_pcm_hw_params *params = &fe->dpcm[stream].hw_params; struct snd_soc_dpcm *dpcm; ssize_t offset = 0; + unsigned long flags; /* FE state */ offset += snprintf(buf + offset, size - offset, @@ -3331,6 +3356,7 @@ static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe, goto out; } + spin_lock_irqsave(&fe->card->dpcm_lock, flags); for_each_dpcm_be(fe, stream, dpcm) { struct snd_soc_pcm_runtime *be = dpcm->be; params = &dpcm->hw_params; @@ -3351,7 +3377,7 @@ static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe, params_channels(params), params_rate(params)); } - + spin_unlock_irqrestore(&fe->card->dpcm_lock, flags); out: return offset; } -- cgit v1.2.3-59-g8ed1b From 844a4a362dbec166b44d6b9b3dd45b08cb273703 Mon Sep 17 00:00:00 2001 From: John Hsu Date: Mon, 11 Mar 2019 09:36:45 +0800 Subject: ASoC: nau8824: fix the issue of the widget with prefix name The driver has two issues when machine add prefix name for codec. (1)The stream name of DAI can't find the AIF widgets. (2)The drivr can enable/disalbe the MICBIAS and SAR widgets. The patch will fix these issues caused by prefixed name added. Signed-off-by: John Hsu Signed-off-by: Mark Brown --- sound/soc/codecs/nau8824.c | 46 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 8 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/nau8824.c b/sound/soc/codecs/nau8824.c index 87ed3dc496dc..5ab05e75edea 100644 --- a/sound/soc/codecs/nau8824.c +++ b/sound/soc/codecs/nau8824.c @@ -681,8 +681,8 @@ static const struct snd_soc_dapm_widget nau8824_dapm_widgets[] = { SND_SOC_DAPM_ADC("ADCR", NULL, NAU8824_REG_ANALOG_ADC_2, NAU8824_ADCR_EN_SFT, 0), - SND_SOC_DAPM_AIF_OUT("AIFTX", "HiFi Capture", 0, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_AIF_IN("AIFRX", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIFTX", "Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("AIFRX", "Playback", 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_DAC("DACL", NULL, NAU8824_REG_RDAC, NAU8824_DACL_EN_SFT, 0), @@ -831,6 +831,36 @@ static void nau8824_int_status_clear_all(struct regmap *regmap) } } +static void nau8824_dapm_disable_pin(struct nau8824 *nau8824, const char *pin) +{ + struct snd_soc_dapm_context *dapm = nau8824->dapm; + const char *prefix = dapm->component->name_prefix; + char prefixed_pin[80]; + + if (prefix) { + snprintf(prefixed_pin, sizeof(prefixed_pin), "%s %s", + prefix, pin); + snd_soc_dapm_disable_pin(dapm, prefixed_pin); + } else { + snd_soc_dapm_disable_pin(dapm, pin); + } +} + +static void nau8824_dapm_enable_pin(struct nau8824 *nau8824, const char *pin) +{ + struct snd_soc_dapm_context *dapm = nau8824->dapm; + const char *prefix = dapm->component->name_prefix; + char prefixed_pin[80]; + + if (prefix) { + snprintf(prefixed_pin, sizeof(prefixed_pin), "%s %s", + prefix, pin); + snd_soc_dapm_force_enable_pin(dapm, prefixed_pin); + } else { + snd_soc_dapm_force_enable_pin(dapm, pin); + } +} + static void nau8824_eject_jack(struct nau8824 *nau8824) { struct snd_soc_dapm_context *dapm = nau8824->dapm; @@ -839,8 +869,8 @@ static void nau8824_eject_jack(struct nau8824 *nau8824) /* Clear all interruption status */ nau8824_int_status_clear_all(regmap); - snd_soc_dapm_disable_pin(dapm, "SAR"); - snd_soc_dapm_disable_pin(dapm, "MICBIAS"); + nau8824_dapm_disable_pin(nau8824, "SAR"); + nau8824_dapm_disable_pin(nau8824, "MICBIAS"); snd_soc_dapm_sync(dapm); /* Enable the insertion interruption, disable the ejection @@ -870,8 +900,8 @@ static void nau8824_jdet_work(struct work_struct *work) struct regmap *regmap = nau8824->regmap; int adc_value, event = 0, event_mask = 0; - snd_soc_dapm_force_enable_pin(dapm, "MICBIAS"); - snd_soc_dapm_force_enable_pin(dapm, "SAR"); + nau8824_dapm_enable_pin(nau8824, "MICBIAS"); + nau8824_dapm_enable_pin(nau8824, "SAR"); snd_soc_dapm_sync(dapm); msleep(100); @@ -882,8 +912,8 @@ static void nau8824_jdet_work(struct work_struct *work) if (adc_value < HEADSET_SARADC_THD) { event |= SND_JACK_HEADPHONE; - snd_soc_dapm_disable_pin(dapm, "SAR"); - snd_soc_dapm_disable_pin(dapm, "MICBIAS"); + nau8824_dapm_disable_pin(nau8824, "SAR"); + nau8824_dapm_disable_pin(nau8824, "MICBIAS"); snd_soc_dapm_sync(dapm); } else { event |= SND_JACK_HEADSET; -- cgit v1.2.3-59-g8ed1b From a39fe6e2061615496c12825d6d249fedf1974f8a Mon Sep 17 00:00:00 2001 From: Olivier Moysan Date: Mon, 11 Mar 2019 16:39:28 +0100 Subject: ASoC: stm32: i2s: fix registers declaration in regmap - Declare SR as volatile, as it is changed by hardware. - Remove TXDR from readable and volatile register list, as it is intended for write accesses only. Signed-off-by: Olivier Moysan Signed-off-by: Mark Brown --- sound/soc/stm/stm32_i2s.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c index 47c334de6b09..8968458eec62 100644 --- a/sound/soc/stm/stm32_i2s.c +++ b/sound/soc/stm/stm32_i2s.c @@ -281,7 +281,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_TXDR_REG: case STM32_I2S_RXDR_REG: case STM32_I2S_CGFR_REG: return true; @@ -293,7 +292,7 @@ static bool stm32_i2s_readable_reg(struct device *dev, unsigned int reg) static bool stm32_i2s_volatile_reg(struct device *dev, unsigned int reg) { switch (reg) { - case STM32_I2S_TXDR_REG: + case STM32_I2S_SR_REG: case STM32_I2S_RXDR_REG: return true; default: -- cgit v1.2.3-59-g8ed1b From ba164a49f8f7390b036713bf8a70a150a938c670 Mon Sep 17 00:00:00 2001 From: Jiada Wang Date: Thu, 7 Mar 2019 15:15:53 +0900 Subject: ASoC: rsnd: src: Avoid a potential deadlock lockdep warns us that priv->lock and k->k_lock can cause a deadlock when after acquire of k->k_lock, process is interrupted by src, while in another routine of src .init, k->k_lock is acquired with priv->lock held. This patch avoids a potential deadlock by not calling soc_device_match() in SRC .init callback, instead it adds new soc fields in priv->flags to differentiate SoCs. Fixes: linux-next commit 7674bec4fc09 ("ASoC: rsnd: update BSDSR/BSDISR handling") Signed-off-by: Jiada Wang Acked-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 2 ++ sound/soc/sh/rcar/rsnd.h | 5 +++++ sound/soc/sh/rcar/src.c | 9 +-------- 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 9834474684b1..8d3758f862f1 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -110,6 +110,8 @@ static const struct of_device_id rsnd_of_match[] = { { .compatible = "renesas,rcar_sound-gen1", .data = (void *)RSND_GEN1 }, { .compatible = "renesas,rcar_sound-gen2", .data = (void *)RSND_GEN2 }, { .compatible = "renesas,rcar_sound-gen3", .data = (void *)RSND_GEN3 }, + /* Special Handling */ + { .compatible = "renesas,rcar_sound-r8a77990", .data = (void *)(RSND_GEN3 | RSND_SOC_E) }, {}, }; MODULE_DEVICE_TABLE(of, rsnd_of_match); diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 90625c57847b..0e6ef4e18400 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -607,6 +607,8 @@ struct rsnd_priv { #define RSND_GEN1 (1 << 0) #define RSND_GEN2 (2 << 0) #define RSND_GEN3 (3 << 0) +#define RSND_SOC_MASK (0xFF << 4) +#define RSND_SOC_E (1 << 4) /* E1/E2/E3 */ /* * below value will be filled on rsnd_gen_probe() @@ -679,6 +681,9 @@ struct rsnd_priv { #define rsnd_is_gen1(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN1) #define rsnd_is_gen2(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN2) #define rsnd_is_gen3(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN3) +#define rsnd_is_e3(priv) (((priv)->flags & \ + (RSND_GEN_MASK | RSND_SOC_MASK)) == \ + (RSND_GEN3 | RSND_SOC_E)) #define rsnd_flags_has(p, f) ((p)->flags & (f)) #define rsnd_flags_set(p, f) ((p)->flags |= (f)) diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index db81e066b92e..45096a66c074 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -14,7 +14,6 @@ */ #include "rsnd.h" -#include #define SRC_NAME "src" @@ -189,18 +188,12 @@ const static u32 chan222222[] = { 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; @@ -307,7 +300,7 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, /* * E3 need to overwrite */ - if (soc) + if (rsnd_is_e3(priv)) switch (rsnd_mod_id(mod)) { case 0: case 4: -- cgit v1.2.3-59-g8ed1b From 399706df420ea8bc8b31283a919e6475f737d0ea Mon Sep 17 00:00:00 2001 From: Jiada Wang Date: Thu, 7 Mar 2019 15:15:54 +0900 Subject: ASoC: rsnd: src: fix compiler warnings compiler complains about following declarations sound/soc/sh/rcar/src.c:174:1: warning: 'static' is not at beginning of declaration [-Wold-style-declaration] const static u32 bsdsr_table_pattern1[] = { ^~~~~ sound/soc/sh/rcar/src.c:183:1: warning: 'static' is not at beginning of declaration [-Wold-style-declaration] const static u32 bsdsr_table_pattern2[] = { ^~~~~ sound/soc/sh/rcar/src.c:192:1: warning: 'static' is not at beginning of declaration [-Wold-style-declaration] const static u32 bsisr_table[] = { ^~~~~ sound/soc/sh/rcar/src.c:201:1: warning: 'static' is not at beginning of declaration [-Wold-style-declaration] const static u32 chan288888[] = { ^~~~~ sound/soc/sh/rcar/src.c:210:1: warning: 'static' is not at beginning of declaration [-Wold-style-declaration] const static u32 chan244888[] = { ^~~~~ sound/soc/sh/rcar/src.c:219:1: warning: 'static' is not at beginning of declaration [-Wold-style-declaration] const static u32 chan222222[] = { ^~~~~ This patch moves the 'static' keyword to the front of the declaration to fix the compiler warnings Fixes: linux-next commit 7674bec4fc09 ("ASoC: rsnd: update BSDSR/BSDISR handling") Signed-off-by: Jiada Wang Acked-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/src.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 45096a66c074..585ffba0244b 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -134,7 +134,7 @@ unsigned int rsnd_src_get_rate(struct rsnd_priv *priv, return rate; } -const static u32 bsdsr_table_pattern1[] = { +static const u32 bsdsr_table_pattern1[] = { 0x01800000, /* 6 - 1/6 */ 0x01000000, /* 6 - 1/4 */ 0x00c00000, /* 6 - 1/3 */ @@ -143,7 +143,7 @@ const static u32 bsdsr_table_pattern1[] = { 0x00400000, /* 6 - 1 */ }; -const static u32 bsdsr_table_pattern2[] = { +static const u32 bsdsr_table_pattern2[] = { 0x02400000, /* 6 - 1/6 */ 0x01800000, /* 6 - 1/4 */ 0x01200000, /* 6 - 1/3 */ @@ -152,7 +152,7 @@ const static u32 bsdsr_table_pattern2[] = { 0x00600000, /* 6 - 1 */ }; -const static u32 bsisr_table[] = { +static const u32 bsisr_table[] = { 0x00100060, /* 6 - 1/6 */ 0x00100040, /* 6 - 1/4 */ 0x00100030, /* 6 - 1/3 */ @@ -161,7 +161,7 @@ const static u32 bsisr_table[] = { 0x00100020, /* 6 - 1 */ }; -const static u32 chan288888[] = { +static const u32 chan288888[] = { 0x00000006, /* 1 to 2 */ 0x000001fe, /* 1 to 8 */ 0x000001fe, /* 1 to 8 */ @@ -170,7 +170,7 @@ const static u32 chan288888[] = { 0x000001fe, /* 1 to 8 */ }; -const static u32 chan244888[] = { +static const u32 chan244888[] = { 0x00000006, /* 1 to 2 */ 0x0000001e, /* 1 to 4 */ 0x0000001e, /* 1 to 4 */ @@ -179,7 +179,7 @@ const static u32 chan244888[] = { 0x000001fe, /* 1 to 8 */ }; -const static u32 chan222222[] = { +static const u32 chan222222[] = { 0x00000006, /* 1 to 2 */ 0x00000006, /* 1 to 2 */ 0x00000006, /* 1 to 2 */ -- cgit v1.2.3-59-g8ed1b From 54d1cf78b0f4ba348a7c7fb8b7d0708d71b6cc8a Mon Sep 17 00:00:00 2001 From: John Hsu Date: Wed, 13 Mar 2019 16:23:44 +0800 Subject: ASoC: nau8810: fix the issue of widget with prefixed name The driver changes the stream name of DAC and ADC to avoid the issue of widget with prefixed name. When the machine adds prefixed name for codec, the stream name of DAI may not find the widgets. Signed-off-by: John Hsu Signed-off-by: Mark Brown --- sound/soc/codecs/nau8810.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/nau8810.c b/sound/soc/codecs/nau8810.c index bfd74b86c9d2..645aa0794123 100644 --- a/sound/soc/codecs/nau8810.c +++ b/sound/soc/codecs/nau8810.c @@ -411,9 +411,9 @@ static const struct snd_soc_dapm_widget nau8810_dapm_widgets[] = { SND_SOC_DAPM_MIXER("Mono Mixer", NAU8810_REG_POWER3, NAU8810_MOUTMX_EN_SFT, 0, &nau8810_mono_mixer_controls[0], ARRAY_SIZE(nau8810_mono_mixer_controls)), - SND_SOC_DAPM_DAC("DAC", "HiFi Playback", NAU8810_REG_POWER3, + SND_SOC_DAPM_DAC("DAC", "Playback", NAU8810_REG_POWER3, NAU8810_DAC_EN_SFT, 0), - SND_SOC_DAPM_ADC("ADC", "HiFi Capture", NAU8810_REG_POWER2, + SND_SOC_DAPM_ADC("ADC", "Capture", NAU8810_REG_POWER2, NAU8810_ADC_EN_SFT, 0), SND_SOC_DAPM_PGA("SpkN Out", NAU8810_REG_POWER3, NAU8810_NSPK_EN_SFT, 0, NULL, 0), -- cgit v1.2.3-59-g8ed1b From 2b13bee3884926cba22061efa75bd315e871de24 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 12 Mar 2019 18:40:06 +0100 Subject: ASoC: samsung: odroid: Fix clock configuration for 44100 sample rate After commit fbeec965b8d1c ("ASoC: samsung: odroid: Fix 32000 sample rate handling") the audio root clock frequency is configured improperly for 44100 sample rate. Due to clock rate rounding it's 20070401 Hz instead of 22579000 Hz. This results in a too low value of the PSR clock divider in the CPU DAI driver and too fast actual sample rate for fs=44100. E.g. 1 kHz tone has actual 1780 Hz frequency (1 kHz * 20070401/22579000 * 2). Fix this by increasing the correction passed to clk_set_rate() to take into account inaccuracy of the EPLL frequency properly. Fixes: fbeec965b8d1c ("ASoC: samsung: odroid: Fix 32000 sample rate handling") Reported-by: JaeChul Lee Signed-off-by: Sylwester Nawrocki Signed-off-by: Mark Brown --- sound/soc/samsung/odroid.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/samsung/odroid.c b/sound/soc/samsung/odroid.c index 694512f980fd..1dc54c4206f0 100644 --- a/sound/soc/samsung/odroid.c +++ b/sound/soc/samsung/odroid.c @@ -91,11 +91,11 @@ static int odroid_card_be_hw_params(struct snd_pcm_substream *substream, return ret; /* - * We add 1 to the rclk_freq value in order to avoid too low clock + * We add 2 to the rclk_freq value in order to avoid too low clock * frequency values due to the EPLL output frequency not being exact * multiple of the audio sampling rate. */ - rclk_freq = params_rate(params) * rfs + 1; + rclk_freq = params_rate(params) * rfs + 2; ret = clk_set_rate(priv->sclk_i2s, rclk_freq); if (ret < 0) -- cgit v1.2.3-59-g8ed1b From 9729e3b65a64dfe210972223624d8152ba502e98 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Thu, 7 Mar 2019 10:35:58 +0800 Subject: ASoC: mediatek: mt8183: skip for i2s5 in mck_disable Skip for i2s5 in mck_disable which is also bypassed in mck_enable. Signed-off-by: Tzung-Bi Shih Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8183/mt8183-afe-clk.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/mediatek/mt8183/mt8183-afe-clk.c b/sound/soc/mediatek/mt8183/mt8183-afe-clk.c index f523ad103acc..48e81c5d52fc 100644 --- a/sound/soc/mediatek/mt8183/mt8183-afe-clk.c +++ b/sound/soc/mediatek/mt8183/mt8183-afe-clk.c @@ -605,6 +605,10 @@ void mt8183_mck_disable(struct mtk_base_afe *afe, int mck_id) int m_sel_id = mck_div[mck_id].m_sel_id; int div_clk_id = mck_div[mck_id].div_clk_id; + /* i2s5 mck not support */ + if (mck_id == MT8183_I2S5_MCK) + return; + clk_disable_unprepare(afe_priv->clk[div_clk_id]); if (m_sel_id >= 0) clk_disable_unprepare(afe_priv->clk[m_sel_id]); -- cgit v1.2.3-59-g8ed1b From 4834d7070c85a5fb69637265dbbb05d13043280c Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Fri, 8 Mar 2019 11:36:08 +0800 Subject: ASoC: rt5682: Check JD status when system resume The IRQ function may not work when system suspend. We remove snd_soc_dapm_force_enable_pin function call to make sure the bias off when idle and run into suspend/resume function. Signed-off-by: Shuming Fan Signed-off-by: Mark Brown --- sound/soc/codecs/rt5682.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index 9d5acd2d04ab..b7e2e9937e6d 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -910,13 +910,20 @@ static int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert) { struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component); - struct snd_soc_dapm_context *dapm = - snd_soc_component_get_dapm(component); unsigned int val, count; if (jack_insert) { - snd_soc_dapm_force_enable_pin(dapm, "CBJ Power"); - snd_soc_dapm_sync(dapm); + + snd_soc_component_update_bits(component, RT5682_PWR_ANLG_1, + RT5682_PWR_VREF2, RT5682_PWR_VREF2); + snd_soc_component_update_bits(component, + RT5682_PWR_ANLG_1, RT5682_PWR_FV2, 0); + usleep_range(15000, 20000); + snd_soc_component_update_bits(component, + RT5682_PWR_ANLG_1, RT5682_PWR_FV2, RT5682_PWR_FV2); + snd_soc_component_update_bits(component, RT5682_PWR_ANLG_3, + RT5682_PWR_CBJ, RT5682_PWR_CBJ); + snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1, RT5682_TRIG_JD_MASK, RT5682_TRIG_JD_HIGH); @@ -944,8 +951,10 @@ static int rt5682_headset_detect(struct snd_soc_component *component, rt5682_enable_push_button_irq(component, false); snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1, RT5682_TRIG_JD_MASK, RT5682_TRIG_JD_LOW); - snd_soc_dapm_disable_pin(dapm, "CBJ Power"); - snd_soc_dapm_sync(dapm); + snd_soc_component_update_bits(component, RT5682_PWR_ANLG_1, + RT5682_PWR_VREF2, 0); + snd_soc_component_update_bits(component, RT5682_PWR_ANLG_3, + RT5682_PWR_CBJ, 0); rt5682->jack_type = 0; } @@ -1591,8 +1600,6 @@ static const struct snd_soc_dapm_widget rt5682_dapm_widgets[] = { 0, NULL, 0), SND_SOC_DAPM_SUPPLY("Vref1", RT5682_PWR_ANLG_1, RT5682_PWR_VREF1_BIT, 0, rt5655_set_verf, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), - SND_SOC_DAPM_SUPPLY("Vref2", RT5682_PWR_ANLG_1, RT5682_PWR_VREF2_BIT, 0, - rt5655_set_verf, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), /* ASRC */ SND_SOC_DAPM_SUPPLY_S("DAC STO1 ASRC", 1, RT5682_PLL_TRACK_1, @@ -1627,9 +1634,6 @@ static const struct snd_soc_dapm_widget rt5682_dapm_widgets[] = { SND_SOC_DAPM_PGA("BST1 CBJ", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("CBJ Power", RT5682_PWR_ANLG_3, - RT5682_PWR_CBJ_BIT, 0, NULL, 0), - /* REC Mixer */ SND_SOC_DAPM_MIXER("RECMIX1L", SND_SOC_NOPM, 0, 0, rt5682_rec1_l_mix, ARRAY_SIZE(rt5682_rec1_l_mix)), @@ -1792,17 +1796,13 @@ static const struct snd_soc_dapm_route rt5682_dapm_routes[] = { /*Vref*/ {"MICBIAS1", NULL, "Vref1"}, - {"MICBIAS1", NULL, "Vref2"}, {"MICBIAS2", NULL, "Vref1"}, - {"MICBIAS2", NULL, "Vref2"}, {"CLKDET SYS", NULL, "CLKDET"}, {"IN1P", NULL, "LDO2"}, {"BST1 CBJ", NULL, "IN1P"}, - {"BST1 CBJ", NULL, "CBJ Power"}, - {"CBJ Power", NULL, "Vref2"}, {"RECMIX1L", "CBJ Switch", "BST1 CBJ"}, {"RECMIX1L", NULL, "RECMIX1L Power"}, @@ -1912,9 +1912,7 @@ static const struct snd_soc_dapm_route rt5682_dapm_routes[] = { {"HP Amp", NULL, "Capless"}, {"HP Amp", NULL, "Charge Pump"}, {"HP Amp", NULL, "CLKDET SYS"}, - {"HP Amp", NULL, "CBJ Power"}, {"HP Amp", NULL, "Vref1"}, - {"HP Amp", NULL, "Vref2"}, {"HPOL Playback", "Switch", "HP Amp"}, {"HPOR Playback", "Switch", "HP Amp"}, {"HPOL", NULL, "HPOL Playback"}, @@ -2363,6 +2361,8 @@ static int rt5682_resume(struct snd_soc_component *component) regcache_cache_only(rt5682->regmap, false); regcache_sync(rt5682->regmap); + rt5682_irq(0, rt5682); + return 0; } #else -- cgit v1.2.3-59-g8ed1b From 675212bfb23394514b7f68ebf3954ba936281ccc Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Mon, 18 Mar 2019 15:17:13 +0800 Subject: ASoC: rt5682: fix jack type detection issue The jack type detection needs the main bias power of analog. The modification makes sure the main bias power on/off while jack plug/unplug. Signed-off-by: Shuming Fan Signed-off-by: Mark Brown --- sound/soc/codecs/rt5682.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index b7e2e9937e6d..b98974edf6ad 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -915,7 +915,8 @@ static int rt5682_headset_detect(struct snd_soc_component *component, if (jack_insert) { snd_soc_component_update_bits(component, RT5682_PWR_ANLG_1, - RT5682_PWR_VREF2, RT5682_PWR_VREF2); + RT5682_PWR_VREF2 | RT5682_PWR_MB, + RT5682_PWR_VREF2 | RT5682_PWR_MB); snd_soc_component_update_bits(component, RT5682_PWR_ANLG_1, RT5682_PWR_FV2, 0); usleep_range(15000, 20000); @@ -952,7 +953,7 @@ static int rt5682_headset_detect(struct snd_soc_component *component, snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1, RT5682_TRIG_JD_MASK, RT5682_TRIG_JD_LOW); snd_soc_component_update_bits(component, RT5682_PWR_ANLG_1, - RT5682_PWR_VREF2, 0); + RT5682_PWR_VREF2 | RT5682_PWR_MB, 0); snd_soc_component_update_bits(component, RT5682_PWR_ANLG_3, RT5682_PWR_CBJ, 0); @@ -2301,16 +2302,13 @@ static int rt5682_set_bias_level(struct snd_soc_component *component, switch (level) { case SND_SOC_BIAS_PREPARE: regmap_update_bits(rt5682->regmap, RT5682_PWR_ANLG_1, - RT5682_PWR_MB | RT5682_PWR_BG, - RT5682_PWR_MB | RT5682_PWR_BG); + RT5682_PWR_BG, RT5682_PWR_BG); regmap_update_bits(rt5682->regmap, RT5682_PWR_DIG_1, RT5682_DIG_GATE_CTRL | RT5682_PWR_LDO, RT5682_DIG_GATE_CTRL | RT5682_PWR_LDO); break; case SND_SOC_BIAS_STANDBY: - regmap_update_bits(rt5682->regmap, RT5682_PWR_ANLG_1, - RT5682_PWR_MB, RT5682_PWR_MB); regmap_update_bits(rt5682->regmap, RT5682_PWR_DIG_1, RT5682_DIG_GATE_CTRL, RT5682_DIG_GATE_CTRL); break; @@ -2318,7 +2316,7 @@ static int rt5682_set_bias_level(struct snd_soc_component *component, regmap_update_bits(rt5682->regmap, RT5682_PWR_DIG_1, RT5682_DIG_GATE_CTRL | RT5682_PWR_LDO, 0); regmap_update_bits(rt5682->regmap, RT5682_PWR_ANLG_1, - RT5682_PWR_MB | RT5682_PWR_BG, 0); + RT5682_PWR_BG, 0); break; default: -- cgit v1.2.3-59-g8ed1b From 1c5b6a27e432e4fe170a924c8b41012271496a4c Mon Sep 17 00:00:00 2001 From: Shuming Fan Date: Mon, 18 Mar 2019 15:17:42 +0800 Subject: ASoC: rt5682: recording has no sound after booting If ASRC turns on, HW will use clk_dac as the reference clock whether recording or playback. Both of clk_dac and clk_adc should set proper clock while using ASRC. Signed-off-by: Shuming Fan Signed-off-by: Mark Brown --- sound/soc/codecs/rt5682.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index b98974edf6ad..86a7fa31c294 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -1208,7 +1208,7 @@ static int set_filter_clk(struct snd_soc_dapm_widget *w, struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component); - int ref, val, reg, sft, mask, idx = -EINVAL; + int ref, val, reg, idx = -EINVAL; static const int div_f[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48}; static const int div_o[] = {1, 2, 4, 6, 8, 12, 16, 24, 32, 48}; @@ -1222,15 +1222,10 @@ static int set_filter_clk(struct snd_soc_dapm_widget *w, idx = rt5682_div_sel(rt5682, ref, div_f, ARRAY_SIZE(div_f)); - if (w->shift == RT5682_PWR_ADC_S1F_BIT) { + if (w->shift == RT5682_PWR_ADC_S1F_BIT) reg = RT5682_PLL_TRACK_3; - sft = RT5682_ADC_OSR_SFT; - mask = RT5682_ADC_OSR_MASK; - } else { + else reg = RT5682_PLL_TRACK_2; - sft = RT5682_DAC_OSR_SFT; - mask = RT5682_DAC_OSR_MASK; - } snd_soc_component_update_bits(component, reg, RT5682_FILTER_CLK_DIV_MASK, idx << RT5682_FILTER_CLK_DIV_SFT); @@ -1242,7 +1237,8 @@ static int set_filter_clk(struct snd_soc_dapm_widget *w, } snd_soc_component_update_bits(component, RT5682_ADDA_CLK_1, - mask, idx << sft); + RT5682_ADC_OSR_MASK | RT5682_DAC_OSR_MASK, + (idx << RT5682_ADC_OSR_SFT) | (idx << RT5682_DAC_OSR_SFT)); return 0; } -- cgit v1.2.3-59-g8ed1b From 639e5eb3c7d67e407f2a71fccd95323751398f6f Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 19 Mar 2019 11:52:04 +0000 Subject: ASoC: wm_adsp: Correct handling of compressed streams that restart Previously support was added to allow streams to be stopped and started again without the DSP being power cycled and this was done by clearing the buffer state in trigger start. Another supported use-case is using the DSP for a trigger event then opening the compressed stream later to receive the audio, unfortunately clearing the buffer state in trigger start destroys the data received from such a trigger. Correct this issue by moving the call to wm_adsp_buffer_clear to be in trigger stop instead. Fixes: 61fc060c40e6 ("ASoC: wm_adsp: Support streams which can start/stop with DSP active") Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index b93fdc8d2d6f..0de36b7eeeb2 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -3571,8 +3571,6 @@ int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd) if (ret < 0) break; - wm_adsp_buffer_clear(compr->buf); - /* Trigger the IRQ at one fragment of data */ ret = wm_adsp_buffer_write(compr->buf, HOST_BUFFER_FIELD(high_water_mark), @@ -3584,6 +3582,7 @@ int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd) } break; case SNDRV_PCM_TRIGGER_STOP: + wm_adsp_buffer_clear(compr->buf); break; default: ret = -EINVAL; -- cgit v1.2.3-59-g8ed1b From 48ead31ce247dc8c0b01ad99d1a97da35421493b Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 19 Mar 2019 11:52:05 +0000 Subject: ASoC: wm_adsp: Correct error messages in wm_adsp_buffer_get_error During recent logging improvements it seems two error messages lost their updates during patch application/rebasing. Add these back in. Fixes: 0d3fba3e7a56 ("ASoC: wm_adsp: Improve logging messages") Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 0de36b7eeeb2..b3348a213c18 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -3535,11 +3535,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; } -- cgit v1.2.3-59-g8ed1b From a2225a6d155fcb247fe4c6d87f7c91807462966d Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 19 Mar 2019 11:52:06 +0000 Subject: ASoC: wm_adsp: Add locking to wm_adsp2_bus_error Best to lock across handling the bus error to ensure the DSP doesn't change power state as we are reading the status registers. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index b3348a213c18..c19a8a041d4d 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -3922,11 +3922,13 @@ irqreturn_t wm_adsp2_bus_error(struct wm_adsp *dsp) struct regmap *regmap = dsp->regmap; int ret = 0; + mutex_lock(&dsp->pwr_lock); + ret = regmap_read(regmap, dsp->base + ADSP2_LOCK_REGION_CTRL, &val); if (ret) { adsp_err(dsp, "Failed to read Region Lock Ctrl register: %d\n", ret); - return IRQ_HANDLED; + goto error; } if (val & ADSP2_WDT_TIMEOUT_STS_MASK) { @@ -3945,7 +3947,7 @@ irqreturn_t wm_adsp2_bus_error(struct wm_adsp *dsp) adsp_err(dsp, "Failed to read Bus Err Addr register: %d\n", ret); - return IRQ_HANDLED; + goto error; } adsp_err(dsp, "bus error address = 0x%x\n", @@ -3958,7 +3960,7 @@ irqreturn_t wm_adsp2_bus_error(struct wm_adsp *dsp) adsp_err(dsp, "Failed to read Pmem Xmem Err Addr register: %d\n", ret); - return IRQ_HANDLED; + goto error; } adsp_err(dsp, "xmem error address = 0x%x\n", @@ -3971,6 +3973,9 @@ irqreturn_t wm_adsp2_bus_error(struct wm_adsp *dsp) regmap_update_bits(regmap, dsp->base + ADSP2_LOCK_REGION_CTRL, ADSP2_CTRL_ERR_EINT, ADSP2_CTRL_ERR_EINT); +error: + mutex_unlock(&dsp->pwr_lock); + return IRQ_HANDLED; } EXPORT_SYMBOL_GPL(wm_adsp2_bus_error); -- cgit v1.2.3-59-g8ed1b From a2bcbc1b9ac2f982a438081a9f1b5d823332d514 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 19 Mar 2019 11:52:07 +0000 Subject: ASoC: wm_adsp: Shutdown any compressed streams on DSP watchdog timeout If a watchdog timeout is received from the DSP it is safe to assume the DSP is not functioning anymore and as such any active compressed streams should be put into an error state. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 21 +++++++++++++++++++++ sound/soc/codecs/wm_adsp.h | 1 + 2 files changed, 22 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index c19a8a041d4d..5608ed5decca 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -2905,6 +2905,8 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, if (wm_adsp_fw[dsp->fw].num_caps != 0) wm_adsp_buffer_free(dsp); + dsp->fatal_error = false; + mutex_unlock(&dsp->pwr_lock); adsp_dbg(dsp, "Execution stopped\n"); @@ -3000,6 +3002,9 @@ static int wm_adsp_compr_attach(struct wm_adsp_compr *compr) { struct wm_adsp_compr_buf *buf = NULL, *tmp; + if (compr->dsp->fatal_error) + return -EINVAL; + list_for_each_entry(tmp, &compr->dsp->buffer_list, list) { if (!tmp->name || !strcmp(compr->name, tmp->name)) { buf = tmp; @@ -3916,6 +3921,21 @@ int wm_adsp2_lock(struct wm_adsp *dsp, unsigned int lock_regions) } EXPORT_SYMBOL_GPL(wm_adsp2_lock); +static void wm_adsp_fatal_error(struct wm_adsp *dsp) +{ + struct wm_adsp_compr *compr; + + dsp->fatal_error = true; + + list_for_each_entry(compr, &dsp->compr_list, list) { + if (compr->stream) { + snd_compr_stop_error(compr->stream, + SNDRV_PCM_STATE_XRUN); + snd_compr_fragment_elapsed(compr->stream); + } + } +} + irqreturn_t wm_adsp2_bus_error(struct wm_adsp *dsp) { unsigned int val; @@ -3934,6 +3954,7 @@ irqreturn_t wm_adsp2_bus_error(struct wm_adsp *dsp) if (val & ADSP2_WDT_TIMEOUT_STS_MASK) { adsp_err(dsp, "watchdog timeout error\n"); wm_adsp_stop_watchdog(dsp); + wm_adsp_fatal_error(dsp); } if (val & (ADSP2_SLAVE_ERR_MASK | ADSP2_REGION_LOCK_ERR_MASK)) { diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index 59e07ad16329..8f09b4419a91 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h @@ -85,6 +85,7 @@ struct wm_adsp { bool preloaded; bool booted; bool running; + bool fatal_error; struct list_head ctl_list; -- cgit v1.2.3-59-g8ed1b From 19441e35a43b616ea6afad91ed0d9e77268d8f6a Mon Sep 17 00:00:00 2001 From: Olivier Moysan Date: Mon, 4 Mar 2019 15:52:43 +0100 Subject: ASoC: stm32: dfsdm: manage multiple prepare The DFSDM must be stopped when a new setting is applied. restart systematically DFSDM on multiple prepare calls, to apply changes. Signed-off-by: Olivier Moysan Signed-off-by: Mark Brown --- sound/soc/stm/stm32_adfsdm.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/stm/stm32_adfsdm.c b/sound/soc/stm/stm32_adfsdm.c index 47901983a6ff..d77f0421e4f0 100644 --- a/sound/soc/stm/stm32_adfsdm.c +++ b/sound/soc/stm/stm32_adfsdm.c @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -37,6 +38,8 @@ struct stm32_adfsdm_priv { /* PCM buffer */ unsigned char *pcm_buff; unsigned int pos; + + struct mutex lock; /* protect against race condition on iio state */ }; static const struct snd_pcm_hardware stm32_adfsdm_pcm_hw = { @@ -62,10 +65,12 @@ static void stm32_adfsdm_shutdown(struct snd_pcm_substream *substream, { struct stm32_adfsdm_priv *priv = snd_soc_dai_get_drvdata(dai); + mutex_lock(&priv->lock); if (priv->iio_active) { iio_channel_stop_all_cb(priv->iio_cb); priv->iio_active = false; } + mutex_unlock(&priv->lock); } static int stm32_adfsdm_dai_prepare(struct snd_pcm_substream *substream, @@ -74,13 +79,19 @@ static int stm32_adfsdm_dai_prepare(struct snd_pcm_substream *substream, struct stm32_adfsdm_priv *priv = snd_soc_dai_get_drvdata(dai); int ret; + mutex_lock(&priv->lock); + if (priv->iio_active) { + iio_channel_stop_all_cb(priv->iio_cb); + priv->iio_active = false; + } + ret = iio_write_channel_attribute(priv->iio_ch, substream->runtime->rate, 0, IIO_CHAN_INFO_SAMP_FREQ); if (ret < 0) { dev_err(dai->dev, "%s: Failed to set %d sampling rate\n", __func__, substream->runtime->rate); - return ret; + goto out; } if (!priv->iio_active) { @@ -92,6 +103,9 @@ static int stm32_adfsdm_dai_prepare(struct snd_pcm_substream *substream, __func__, ret); } +out: + mutex_unlock(&priv->lock); + return ret; } @@ -299,6 +313,7 @@ static int stm32_adfsdm_probe(struct platform_device *pdev) priv->dev = &pdev->dev; priv->dai_drv = stm32_adfsdm_dai; + mutex_init(&priv->lock); dev_set_drvdata(&pdev->dev, priv); -- cgit v1.2.3-59-g8ed1b From c47255b61129857b74b0d86eaf59335348be05e0 Mon Sep 17 00:00:00 2001 From: Olivier Moysan Date: Mon, 4 Mar 2019 15:52:44 +0100 Subject: ASoC: stm32: dfsdm: fix debugfs warnings on entry creation Register platform component with a prefix, to avoid warnings on debugfs entries creation, due to component name redundancy. Signed-off-by: Olivier Moysan Signed-off-by: Mark Brown --- sound/soc/stm/stm32_adfsdm.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/stm/stm32_adfsdm.c b/sound/soc/stm/stm32_adfsdm.c index d77f0421e4f0..78bed9734713 100644 --- a/sound/soc/stm/stm32_adfsdm.c +++ b/sound/soc/stm/stm32_adfsdm.c @@ -305,6 +305,7 @@ MODULE_DEVICE_TABLE(of, stm32_adfsdm_of_match); static int stm32_adfsdm_probe(struct platform_device *pdev) { struct stm32_adfsdm_priv *priv; + struct snd_soc_component *component; int ret; priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); @@ -332,9 +333,15 @@ static int stm32_adfsdm_probe(struct platform_device *pdev) if (IS_ERR(priv->iio_cb)) return PTR_ERR(priv->iio_cb); - ret = devm_snd_soc_register_component(&pdev->dev, - &stm32_adfsdm_soc_platform, - NULL, 0); + component = devm_kzalloc(&pdev->dev, sizeof(*component), GFP_KERNEL); + if (!component) + return -ENOMEM; +#ifdef CONFIG_DEBUG_FS + component->debugfs_prefix = "pcm"; +#endif + + ret = snd_soc_add_component(&pdev->dev, component, + &stm32_adfsdm_soc_platform, NULL, 0); if (ret < 0) dev_err(&pdev->dev, "%s: Failed to register PCM platform\n", __func__); @@ -342,12 +349,20 @@ static int stm32_adfsdm_probe(struct platform_device *pdev) return ret; } +static int stm32_adfsdm_remove(struct platform_device *pdev) +{ + snd_soc_unregister_component(&pdev->dev); + + return 0; +} + static struct platform_driver stm32_adfsdm_driver = { .driver = { .name = STM32_ADFSDM_DRV_NAME, .of_match_table = stm32_adfsdm_of_match, }, .probe = stm32_adfsdm_probe, + .remove = stm32_adfsdm_remove, }; module_platform_driver(stm32_adfsdm_driver); -- cgit v1.2.3-59-g8ed1b From f0f2338a9cfaf71db895fa989ea7234e8a9b471d Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 20 Mar 2019 22:41:56 +0100 Subject: ASoC: cs4270: Set auto-increment bit for register writes The CS4270 does not by default increment the register address on consecutive writes. During normal operation it doesn't matter as all register accesses are done individually. At resume time after suspend, however, the regcache code gathers the biggest possible block of registers to sync and sends them one on one go. To fix this, set the INCR bit in all cases. Signed-off-by: Daniel Mack Signed-off-by: Mark Brown --- sound/soc/codecs/cs4270.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/soc') diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 33d74f163bd7..793a14d58667 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -642,6 +642,7 @@ static const struct regmap_config cs4270_regmap = { .reg_defaults = cs4270_reg_defaults, .num_reg_defaults = ARRAY_SIZE(cs4270_reg_defaults), .cache_type = REGCACHE_RBTREE, + .write_flag_mask = CS4270_I2C_INCR, .readable_reg = cs4270_reg_is_readable, .volatile_reg = cs4270_reg_is_volatile, -- cgit v1.2.3-59-g8ed1b From 53f67a78663811968f426d480bc55887d787bd94 Mon Sep 17 00:00:00 2001 From: "S.j. Wang" Date: Sat, 2 Mar 2019 05:52:19 +0000 Subject: ASoC: fsl_asrc: add constraint for the asrc of older version There is a constraint for the channel number setting on the asrc of older version (e.g. imx35), the channel number should be even, odd number isn't valid. So add this constraint when the asrc of older version is used. Acked-by: Nicolin Chen Signed-off-by: Shengjiu Wang Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_asrc.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index 528e8b108422..0b937924d2e4 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -445,6 +445,19 @@ struct dma_chan *fsl_asrc_get_dma_channel(struct fsl_asrc_pair *pair, bool dir) } EXPORT_SYMBOL_GPL(fsl_asrc_get_dma_channel); +static int fsl_asrc_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct fsl_asrc *asrc_priv = snd_soc_dai_get_drvdata(dai); + + /* Odd channel number is not valid for older ASRC (channel_bits==3) */ + if (asrc_priv->channel_bits == 3) + snd_pcm_hw_constraint_step(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_CHANNELS, 2); + + return 0; +} + static int fsl_asrc_dai_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -539,6 +552,7 @@ static int fsl_asrc_dai_trigger(struct snd_pcm_substream *substream, int cmd, } static const struct snd_soc_dai_ops fsl_asrc_dai_ops = { + .startup = fsl_asrc_dai_startup, .hw_params = fsl_asrc_dai_hw_params, .hw_free = fsl_asrc_dai_hw_free, .trigger = fsl_asrc_dai_trigger, -- cgit v1.2.3-59-g8ed1b From 0ff4e8c61b794a4bf6c854ab071a1abaaa80f358 Mon Sep 17 00:00:00 2001 From: "S.j. Wang" Date: Wed, 27 Feb 2019 06:31:12 +0000 Subject: ASoC: fsl_esai: fix channel swap issue when stream starts There is very low possibility ( < 0.1% ) that channel swap happened in beginning when multi output/input pin is enabled. The issue is that hardware can't send data to correct pin in the beginning with the normal enable flow. This is hardware issue, but there is no errata, the workaround flow is that: Each time playback/recording, firstly clear the xSMA/xSMB, then enable TE/RE, then enable xSMB and xSMA (xSMB must be enabled before xSMA). Which is to use the xSMA as the trigger start register, previously the xCR_TE or xCR_RE is the bit for starting. Fixes commit 43d24e76b698 ("ASoC: fsl_esai: Add ESAI CPU DAI driver") Cc: Reviewed-by: Fabio Estevam Acked-by: Nicolin Chen Signed-off-by: Shengjiu Wang Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_esai.c | 47 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 10 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index afe67c865330..3623aa9a6f2e 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -54,6 +54,8 @@ struct fsl_esai { u32 fifo_depth; u32 slot_width; u32 slots; + u32 tx_mask; + u32 rx_mask; u32 hck_rate[2]; u32 sck_rate[2]; bool hck_dir[2]; @@ -361,21 +363,13 @@ static int fsl_esai_set_dai_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, regmap_update_bits(esai_priv->regmap, REG_ESAI_TCCR, ESAI_xCCR_xDC_MASK, ESAI_xCCR_xDC(slots)); - regmap_update_bits(esai_priv->regmap, REG_ESAI_TSMA, - ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(tx_mask)); - regmap_update_bits(esai_priv->regmap, REG_ESAI_TSMB, - ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(tx_mask)); - regmap_update_bits(esai_priv->regmap, REG_ESAI_RCCR, ESAI_xCCR_xDC_MASK, ESAI_xCCR_xDC(slots)); - regmap_update_bits(esai_priv->regmap, REG_ESAI_RSMA, - ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(rx_mask)); - regmap_update_bits(esai_priv->regmap, REG_ESAI_RSMB, - ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(rx_mask)); - esai_priv->slot_width = slot_width; esai_priv->slots = slots; + esai_priv->tx_mask = tx_mask; + esai_priv->rx_mask = rx_mask; return 0; } @@ -596,6 +590,7 @@ static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd, bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; u8 i, channels = substream->runtime->channels; u32 pins = DIV_ROUND_UP(channels, esai_priv->slots); + u32 mask; switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -608,15 +603,38 @@ static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd, for (i = 0; tx && i < channels; i++) regmap_write(esai_priv->regmap, REG_ESAI_ETDR, 0x0); + /* + * When set the TE/RE in the end of enablement flow, there + * will be channel swap issue for multi data line case. + * In order to workaround this issue, we switch the bit + * enablement sequence to below sequence + * 1) clear the xSMB & xSMA: which is done in probe and + * stop state. + * 2) set TE/RE + * 3) set xSMB + * 4) set xSMA: xSMA is the last one in this flow, which + * will trigger esai to start. + */ regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK, tx ? ESAI_xCR_TE(pins) : ESAI_xCR_RE(pins)); + mask = tx ? esai_priv->tx_mask : esai_priv->rx_mask; + + regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMB(tx), + ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(mask)); + regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMA(tx), + ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(mask)); + break; case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK, 0); + regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMA(tx), + ESAI_xSMA_xS_MASK, 0); + regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMB(tx), + ESAI_xSMB_xS_MASK, 0); /* Disable and reset FIFO */ regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), @@ -906,6 +924,15 @@ static int fsl_esai_probe(struct platform_device *pdev) return ret; } + esai_priv->tx_mask = 0xFFFFFFFF; + esai_priv->rx_mask = 0xFFFFFFFF; + + /* Clear the TSMA, TSMB, RSMA, RSMB */ + regmap_write(esai_priv->regmap, REG_ESAI_TSMA, 0); + regmap_write(esai_priv->regmap, REG_ESAI_TSMB, 0); + regmap_write(esai_priv->regmap, REG_ESAI_RSMA, 0); + regmap_write(esai_priv->regmap, REG_ESAI_RSMB, 0); + ret = devm_snd_soc_register_component(&pdev->dev, &fsl_esai_component, &fsl_esai_dai, 1); if (ret) { -- cgit v1.2.3-59-g8ed1b From 8f71370f4b02730e8c27faf460af7a3586e24e1f Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Fri, 22 Mar 2019 15:39:48 -0700 Subject: ASoC: intel: Fix crash at suspend/resume after failed codec registration If codec registration fails after the ASoC Intel SST driver has been probed, the kernel will Oops and crash at suspend/resume. general protection fault: 0000 [#1] PREEMPT SMP KASAN PTI CPU: 1 PID: 2811 Comm: cat Tainted: G W 4.19.30 #15 Hardware name: GOOGLE Clapper, BIOS Google_Clapper.5216.199.7 08/22/2014 RIP: 0010:snd_soc_suspend+0x5a/0xd21 Code: 03 80 3c 10 00 49 89 d7 74 0b 48 89 df e8 71 72 c4 fe 4c 89 fa 48 8b 03 48 89 45 d0 48 8d 98 a0 01 00 00 48 89 d8 48 c1 e8 03 <8a> 04 10 84 c0 0f 85 85 0c 00 00 80 3b 00 0f 84 6b 0c 00 00 48 8b RSP: 0018:ffff888035407750 EFLAGS: 00010202 RAX: 0000000000000034 RBX: 00000000000001a0 RCX: 0000000000000000 RDX: dffffc0000000000 RSI: 0000000000000008 RDI: ffff88805c417098 RBP: ffff8880354077b0 R08: dffffc0000000000 R09: ffffed100b975718 R10: 0000000000000001 R11: ffffffff949ea4a3 R12: 1ffff1100b975746 R13: dffffc0000000000 R14: ffff88805cba4588 R15: dffffc0000000000 FS: 0000794a78e91b80(0000) GS:ffff888068d00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007bd5283ccf58 CR3: 000000004b7aa000 CR4: 00000000001006e0 Call Trace: ? dpm_complete+0x67b/0x67b ? i915_gem_suspend+0x14d/0x1ad sst_soc_prepare+0x91/0x1dd ? sst_be_hw_params+0x7e/0x7e dpm_prepare+0x39a/0x88b dpm_suspend_start+0x13/0x9d suspend_devices_and_enter+0x18f/0xbd7 ? arch_suspend_enable_irqs+0x11/0x11 ? printk+0xd9/0x12d ? lock_release+0x95f/0x95f ? log_buf_vmcoreinfo_setup+0x131/0x131 ? rcu_read_lock_sched_held+0x140/0x22a ? __bpf_trace_rcu_utilization+0xa/0xa ? __pm_pr_dbg+0x186/0x190 ? pm_notifier_call_chain+0x39/0x39 ? suspend_test+0x9d/0x9d pm_suspend+0x2f4/0x728 ? trace_suspend_resume+0x3da/0x3da ? lock_release+0x95f/0x95f ? kernfs_fop_write+0x19f/0x32d state_store+0xd8/0x147 ? sysfs_kf_read+0x155/0x155 kernfs_fop_write+0x23e/0x32d __vfs_write+0x108/0x608 ? vfs_read+0x2e9/0x2e9 ? rcu_read_lock_sched_held+0x140/0x22a ? __bpf_trace_rcu_utilization+0xa/0xa ? debug_smp_processor_id+0x10/0x10 ? selinux_file_permission+0x1c5/0x3c8 ? rcu_sync_lockdep_assert+0x6a/0xad ? __sb_start_write+0x129/0x2ac vfs_write+0x1aa/0x434 ksys_write+0xfe/0x1be ? __ia32_sys_read+0x82/0x82 do_syscall_64+0xcd/0x120 entry_SYSCALL_64_after_hwframe+0x49/0xbe In the observed situation, the problem is seen because the codec driver failed to probe due to a hardware problem. max98090 i2c-193C9890:00: Failed to read device revision: -1 max98090 i2c-193C9890:00: ASoC: failed to probe component -1 cht-bsw-max98090 cht-bsw-max98090: ASoC: failed to instantiate card -1 cht-bsw-max98090 cht-bsw-max98090: snd_soc_register_card failed -1 cht-bsw-max98090: probe of cht-bsw-max98090 failed with error -1 The problem is similar to the problem solved with commit 2fc995a87f2e ("ASoC: intel: Fix crash at suspend/resume without card registration"), but codec registration fails at a later point. At that time, the pointer checked with the above mentioned commit is already set, but it is not cleared if the device is subsequently removed. Adding a remove function to clear the pointer fixes the problem. Cc: stable@vger.kernel.org Cc: Jarkko Nikula Cc: Curtis Malainey Signed-off-by: Guenter Roeck Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst-mfld-platform-pcm.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index 08cea5b5cda9..0e8b1c5eec88 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -706,9 +706,17 @@ static int sst_soc_probe(struct snd_soc_component *component) return sst_dsp_init_v2_dpcm(component); } +static void sst_soc_remove(struct snd_soc_component *component) +{ + struct sst_data *drv = dev_get_drvdata(component->dev); + + drv->soc_card = NULL; +} + static const struct snd_soc_component_driver sst_soc_platform_drv = { .name = DRV_NAME, .probe = sst_soc_probe, + .remove = sst_soc_remove, .ops = &sst_platform_ops, .compr_ops = &sst_platform_compr_ops, .pcm_new = sst_pcm_new, -- cgit v1.2.3-59-g8ed1b From cacea3a90e211f0c111975535508d446a4a928d2 Mon Sep 17 00:00:00 2001 From: Pankaj Bharadiya Date: Fri, 22 Mar 2019 18:00:09 +0530 Subject: ASoC: dapm: Fix NULL pointer dereference in snd_soc_dapm_free_kcontrol w_text_param can be NULL and it is being dereferenced without checking. Add the missing sanity check to prevent NULL pointer dereference. Signed-off-by: Pankaj Bharadiya Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 1ec06ef6d161..67b032ca1601 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3957,6 +3957,10 @@ snd_soc_dapm_free_kcontrol(struct snd_soc_card *card, int count; devm_kfree(card->dev, (void *)*private_value); + + if (!w_param_text) + return; + for (count = 0 ; count < num_params; count++) devm_kfree(card->dev, (void *)w_param_text[count]); devm_kfree(card->dev, w_param_text); -- cgit v1.2.3-59-g8ed1b From 36e075ce74ec4e261a638bf09d10b3348ca4d883 Mon Sep 17 00:00:00 2001 From: Jenny TC Date: Sat, 23 Mar 2019 18:40:10 +0530 Subject: ASoC: Intel: Skylake: enable S24_LE format support To enable S24_LE format, sample_type in topology fw has to be set to 1. But sample_type defined in topology firmware configuration is not getting reflected in the dsp param. This patch sets sample_type in base config so that the sample type defined in the topology firmware is reflected in the dsp params. This issues was uncovered while debugging the S24_LE format which require the MSB byte in 32 bit word to be skipped. Setting sample_type in topology firmware to 1 helps to skip MSB byte word. Signed-off-by: Jenny TC Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-messages.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/soc') diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index 28c4806b196a..4bf70b4429f0 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -483,6 +483,7 @@ static void skl_set_base_module_format(struct skl_sst *ctx, base_cfg->audio_fmt.bit_depth = format->bit_depth; base_cfg->audio_fmt.valid_bit_depth = format->valid_bit_depth; base_cfg->audio_fmt.ch_cfg = format->ch_cfg; + base_cfg->audio_fmt.sample_type = format->sample_type; dev_dbg(ctx->dev, "bit_depth=%x valid_bd=%x ch_config=%x\n", format->bit_depth, format->valid_bit_depth, -- cgit v1.2.3-59-g8ed1b From c63adb28f6d913310430f14c69f0a2ea55eed0cc Mon Sep 17 00:00:00 2001 From: Annaliese McDermond Date: Sat, 30 Mar 2019 09:02:02 -0700 Subject: ASoC: tlv320aic32x4: Fix Common Pins The common pins were mistakenly not added to the DAPM graph. Adding these pins will allow valid graphs to be created. Signed-off-by: Annaliese McDermond Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic32x4.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index 96f1526cb258..5520044929f4 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -490,6 +490,8 @@ static const struct snd_soc_dapm_widget aic32x4_dapm_widgets[] = { SND_SOC_DAPM_INPUT("IN2_R"), SND_SOC_DAPM_INPUT("IN3_L"), SND_SOC_DAPM_INPUT("IN3_R"), + SND_SOC_DAPM_INPUT("CM_L"), + SND_SOC_DAPM_INPUT("CM_R"), }; static const struct snd_soc_dapm_route aic32x4_dapm_routes[] = { -- cgit v1.2.3-59-g8ed1b From 6246f283d5e02ac757bd8d9bacde8fdc54c4582d Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Mon, 1 Apr 2019 15:03:54 +0200 Subject: ASoC: dpcm: skip missing substream while applying symmetry If for any reason, the backend does not have the requested substream (like capture on a playback only backend), the BE will be skipped in dpcm_be_dai_startup(). However, dpcm_apply_symmetry() does not skip those BE and will dereference the be_substream (NULL) pointer anyway. Like in dpcm_be_dai_startup(), just skip those BE. Fixes: 906c7d690c3b ("ASoC: dpcm: Apply symmetry for DPCM") Signed-off-by: Jerome Brunet Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 7fe5321000e8..2d5d5cac4ba6 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1911,10 +1911,15 @@ static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream, struct snd_soc_pcm_runtime *be = dpcm->be; struct snd_pcm_substream *be_substream = snd_soc_dpcm_get_substream(be, stream); - struct snd_soc_pcm_runtime *rtd = be_substream->private_data; + struct snd_soc_pcm_runtime *rtd; struct snd_soc_dai *codec_dai; int i; + /* A backend may not have the requested substream */ + if (!be_substream) + continue; + + rtd = be_substream->private_data; if (rtd->dai_link->be_hw_params_fixup) continue; -- cgit v1.2.3-59-g8ed1b From 6e3bfcff191ec9476ca5ef9b2ad85a15ba829374 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 1 Mar 2019 19:08:53 -0600 Subject: ASoC: dapm: set power_check callback for widgets that shouldnt be always on Currently, buffers, schedulers, src's, encoders, decoders and effect type dapm widgets remain always on as their power_check method is not set. Setting this callback allows these widgets in the audio path to be powered managed properly. Signed-off-by: Ranjani Sridharan Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 67b032ca1601..0382a47b30bd 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3650,6 +3650,13 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, case snd_soc_dapm_dac: case snd_soc_dapm_aif_in: case snd_soc_dapm_pga: + case snd_soc_dapm_buffer: + case snd_soc_dapm_scheduler: + case snd_soc_dapm_effect: + case snd_soc_dapm_src: + case snd_soc_dapm_asrc: + case snd_soc_dapm_encoder: + case snd_soc_dapm_decoder: case snd_soc_dapm_out_drv: case snd_soc_dapm_micbias: case snd_soc_dapm_line: -- cgit v1.2.3-59-g8ed1b From 43d147be5738a9ed6cfb25c285ac50d6dd5793be Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 2 Apr 2019 13:49:14 +0100 Subject: ASoC: wm_adsp: Check for buffer in trigger stop Trigger stop can be called in situations where trigger start failed and as such it can't be assumed the buffer is already attached to the compressed stream or a NULL pointer may be dereferenced. Fixes: 639e5eb3c7d6 ("ASoC: wm_adsp: Correct handling of compressed streams that restart") Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 5608ed5decca..b0b48eb9c7c9 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -3587,7 +3587,8 @@ int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd) } break; case SNDRV_PCM_TRIGGER_STOP: - wm_adsp_buffer_clear(compr->buf); + if (wm_adsp_compr_attached(compr)) + wm_adsp_buffer_clear(compr->buf); break; default: ret = -EINVAL; -- cgit v1.2.3-59-g8ed1b From 4bcdec39c454c4e8f9512115bdcc3efec1ba5f55 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 2 Apr 2019 12:20:49 +0200 Subject: ASoC: Intel: cht_bsw_max98090_ti: Enable codec clock once and keep it enabled Users have been seeing sound stability issues with max98090 codecs since: commit 648e921888ad ("clk: x86: Stop marking clocks as CLK_IS_CRITICAL") At first that commit broke sound for Chromebook Swanky and Clapper models, the problem was that the machine-driver has been controlling the wrong clock on those models since support for them was added. This was hidden by clk-pmc-atom.c keeping the actual clk on unconditionally. With the machine-driver controlling the proper clock, sound works again but we are seeing bug reports describing it as: low volume, "sounds like played at 10x speed" and instable. When these issues are hit the following message is seen in dmesg: "max98090 i2c-193C9890:00: PLL unlocked". Attempts have been made to fix this by inserting a delay between enabling the clk and enabling and checking the pll, but this has not helped. It seems that at least on boards which use pmc_plt_clk_0 as clock, if we ever disable the clk, the pll looses its lock and after that we get various issues. This commit fixes this by enabling the clock once at probe time on these boards. In essence this restores the old behavior of clk-pmc-atom.c always keeping the clk on on these boards. Fixes: 648e921888ad ("clk: x86: Stop marking clocks as CLK_IS_CRITICAL") Reported-by: Mogens Jensen Reported-by: Dean Wallace Signed-off-by: Hans de Goede Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/cht_bsw_max98090_ti.c | 47 ++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 6 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c index 3263b0495853..c0e0844f75b9 100644 --- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c +++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c @@ -43,6 +43,7 @@ struct cht_mc_private { struct clk *mclk; struct snd_soc_jack jack; bool ts3a227e_present; + int quirks; }; static int platform_clock_control(struct snd_soc_dapm_widget *w, @@ -54,6 +55,10 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card); int ret; + /* See the comment in snd_cht_mc_probe() */ + if (ctx->quirks & QUIRK_PMC_PLT_CLK_0) + return 0; + codec_dai = snd_soc_card_get_codec_dai(card, CHT_CODEC_DAI); if (!codec_dai) { dev_err(card->dev, "Codec dai not found; Unable to set platform clock\n"); @@ -223,6 +228,10 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) "jack detection gpios not added, error %d\n", ret); } + /* See the comment in snd_cht_mc_probe() */ + if (ctx->quirks & QUIRK_PMC_PLT_CLK_0) + return 0; + /* * The firmware might enable the clock at * boot (this information may or may not @@ -423,16 +432,15 @@ static int snd_cht_mc_probe(struct platform_device *pdev) 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); - if (dmi_id) - quirks = (unsigned long)dmi_id->driver_data; drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); if (!drv) return -ENOMEM; + dmi_id = dmi_first_match(cht_max98090_quirk_table); + if (dmi_id) + drv->quirks = (unsigned long)dmi_id->driver_data; + drv->ts3a227e_present = acpi_dev_found("104C227E"); if (!drv->ts3a227e_present) { /* no need probe TI jack detection chip */ @@ -458,7 +466,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev) snd_soc_card_cht.dev = &pdev->dev; snd_soc_card_set_drvdata(&snd_soc_card_cht, drv); - if (quirks & QUIRK_PMC_PLT_CLK_0) + if (drv->quirks & QUIRK_PMC_PLT_CLK_0) mclk_name = "pmc_plt_clk_0"; else mclk_name = "pmc_plt_clk_3"; @@ -471,6 +479,21 @@ static int snd_cht_mc_probe(struct platform_device *pdev) return PTR_ERR(drv->mclk); } + /* + * Boards which have the MAX98090's clk connected to clk_0 do not seem + * to like it if we muck with the clock. If we disable the clock when + * it is unused we get "max98090 i2c-193C9890:00: PLL unlocked" errors + * and the PLL never seems to lock again. + * So for these boards we enable it here once and leave it at that. + */ + if (drv->quirks & QUIRK_PMC_PLT_CLK_0) { + ret_val = clk_prepare_enable(drv->mclk); + if (ret_val < 0) { + dev_err(&pdev->dev, "MCLK enable error: %d\n", ret_val); + return ret_val; + } + } + ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht); if (ret_val) { dev_err(&pdev->dev, @@ -481,11 +504,23 @@ static int snd_cht_mc_probe(struct platform_device *pdev) return ret_val; } +static int snd_cht_mc_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct cht_mc_private *ctx = snd_soc_card_get_drvdata(card); + + if (ctx->quirks & QUIRK_PMC_PLT_CLK_0) + clk_disable_unprepare(ctx->mclk); + + return 0; +} + static struct platform_driver snd_cht_mc_driver = { .driver = { .name = "cht-bsw-max98090", }, .probe = snd_cht_mc_probe, + .remove = snd_cht_mc_remove, }; module_platform_driver(snd_cht_mc_driver) -- cgit v1.2.3-59-g8ed1b From 7297ba6c74c5b9e78d8e936af82eecfcf7d32dfb Mon Sep 17 00:00:00 2001 From: Annaliese McDermond Date: Wed, 3 Apr 2019 21:17:15 -0700 Subject: ASoC: tlv320aic32x4: Change author's name The author of these files has changed her name. Update instances in the code of her dead name to current legal name. Signed-off-by: Annaliese McDermond Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic32x4-i2c.c | 4 ++-- sound/soc/codecs/tlv320aic32x4-spi.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/codecs/tlv320aic32x4-i2c.c b/sound/soc/codecs/tlv320aic32x4-i2c.c index 385fa2e9525a..22c3a6bc0b6c 100644 --- a/sound/soc/codecs/tlv320aic32x4-i2c.c +++ b/sound/soc/codecs/tlv320aic32x4-i2c.c @@ -3,7 +3,7 @@ * * Copyright 2011 NW Digital Radio * - * Author: Jeremy McDermond + * Author: Annaliese McDermond * * Based on sound/soc/codecs/wm8974 and TI driver for kernel 2.6.27. * @@ -72,5 +72,5 @@ static struct i2c_driver aic32x4_i2c_driver = { module_i2c_driver(aic32x4_i2c_driver); MODULE_DESCRIPTION("ASoC TLV320AIC32x4 codec driver I2C"); -MODULE_AUTHOR("Jeremy McDermond "); +MODULE_AUTHOR("Annaliese McDermond "); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/tlv320aic32x4-spi.c b/sound/soc/codecs/tlv320aic32x4-spi.c index 07d78ae51e05..aa5b7ba0254b 100644 --- a/sound/soc/codecs/tlv320aic32x4-spi.c +++ b/sound/soc/codecs/tlv320aic32x4-spi.c @@ -3,7 +3,7 @@ * * Copyright 2011 NW Digital Radio * - * Author: Jeremy McDermond + * Author: Annaliese McDermond * * Based on sound/soc/codecs/wm8974 and TI driver for kernel 2.6.27. * @@ -74,5 +74,5 @@ static struct spi_driver aic32x4_spi_driver = { module_spi_driver(aic32x4_spi_driver); MODULE_DESCRIPTION("ASoC TLV320AIC32x4 codec driver SPI"); -MODULE_AUTHOR("Jeremy McDermond "); +MODULE_AUTHOR("Annaliese McDermond "); MODULE_LICENSE("GPL"); -- cgit v1.2.3-59-g8ed1b From c2c616021d64d952dc9d37793924ce57833d7754 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 4 Apr 2019 09:52:15 +0900 Subject: ASoC: audio-graph-card: don't select DPCM via audio-graph-card commit ae3cb5790906b ("ASoC: audio-graph-card: merge audio-graph-scu-card") merged audio-graph-scu-card which can handle DPCM into audio-graph-card. By this patch, the judgement to select "normal sound card" or "DPCM sound card" is based on its OF-graph endpoint connection. But, because of it, existing "audio-graph-card" user who is assuming "normal sound card" might select DPCM unintentionally. To solve this issue, this patch allows "audio-graph-card" user can select "normal sound card", and "audio-graph-scu-card" user can select both "normal sound card" and "DPCM sound card". This keeps compatibility collectry. Fixes: ae3cb5790906b ("ASoC: audio-graph-card: merge audio-graph-scu-card") Reported-by: Arnaud Pouliquen Signed-off-by: Kuninori Morimoto Acked-by: Arnaud Pouliquen Signed-off-by: Mark Brown --- sound/soc/generic/audio-graph-card.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index bb12351330e8..69bc4848d787 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -20,6 +20,8 @@ #include #include +#define DPCM_SELECTABLE 1 + struct graph_priv { struct snd_soc_card snd_card; struct graph_dai_props { @@ -440,6 +442,7 @@ static int graph_for_each_link(struct graph_priv *priv, struct device_node *codec_port; struct device_node *codec_port_old = NULL; struct asoc_simple_card_data adata; + uintptr_t dpcm_selectable = (uintptr_t)of_device_get_match_data(dev); int rc, ret; /* loop for all listed CPU port */ @@ -470,8 +473,9 @@ static int graph_for_each_link(struct graph_priv *priv, * 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) + if (dpcm_selectable && + ((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 */ @@ -732,7 +736,8 @@ static int graph_remove(struct platform_device *pdev) static const struct of_device_id graph_of_match[] = { { .compatible = "audio-graph-card", }, - { .compatible = "audio-graph-scu-card", }, + { .compatible = "audio-graph-scu-card", + .data = (void *)DPCM_SELECTABLE }, {}, }; MODULE_DEVICE_TABLE(of, graph_of_match); -- cgit v1.2.3-59-g8ed1b From 42bf029a55a9bb8036f1d738a28dba2f7ec1e79d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 4 Apr 2019 09:52:52 +0900 Subject: ASoC: simple-card: don't select DPCM via simple-audio-card commit da215354eb55c ("ASoC: simple-card: merge simple-scu-card") merged simple-scu-audio-card which can handle DPCM into simple-audio-card. By this patch, the judgement to select "normal sound card" or "DPCM sound card" is based on its CPU/Codec DAI count. But, because of it, existing "simple-audio-card" user who is assuming "normal sound card" might select DPCM unintentionally. To solve this issue, this patch allows "simple-audio-card" user can select "normal sound card", and "simple-scu-audio-card" user can select both "normal sound card" and "DPCM sound card". This keeps compatibility collectry. Fixes: da215354eb55c ("ASoC: simple-card: merge simple-scu-card") Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 7147bba45a2a..34de32efc4c4 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -9,12 +9,15 @@ #include #include #include +#include #include #include #include #include #include +#define DPCM_SELECTABLE 1 + struct simple_priv { struct snd_soc_card snd_card; struct simple_dai_props { @@ -441,6 +444,7 @@ static int simple_for_each_link(struct simple_priv *priv, struct device *dev = simple_priv_to_dev(priv); struct device_node *top = dev->of_node; struct device_node *node; + uintptr_t dpcm_selectable = (uintptr_t)of_device_get_match_data(dev); bool is_top = 0; int ret = 0; @@ -480,8 +484,9 @@ static int simple_for_each_link(struct simple_priv *priv, * if it has many CPUs, * or has convert-xxx property */ - if (num > 2 || - adata.convert_rate || adata.convert_channels) + if (dpcm_selectable && + (num > 2 || + adata.convert_rate || adata.convert_channels)) ret = func_dpcm(priv, np, codec, li, is_top); /* else normal sound */ else @@ -822,7 +827,8 @@ static int simple_remove(struct platform_device *pdev) static const struct of_device_id simple_of_match[] = { { .compatible = "simple-audio-card", }, - { .compatible = "simple-scu-audio-card", }, + { .compatible = "simple-scu-audio-card", + .data = (void *)DPCM_SELECTABLE }, {}, }; MODULE_DEVICE_TABLE(of, simple_of_match); -- cgit v1.2.3-59-g8ed1b From c85064435fe7a216ec0f0238ef2b8f7cd850a450 Mon Sep 17 00:00:00 2001 From: Sugar Zhang Date: Wed, 3 Apr 2019 21:40:45 +0800 Subject: ASoC: rockchip: pdm: fix regmap_ops hang issue This is because set_fmt ops maybe called when PD is off, and in such case, regmap_ops will lead system hang. enale PD before doing regmap_ops. Signed-off-by: Sugar Zhang Signed-off-by: Mark Brown --- sound/soc/rockchip/rockchip_pdm.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/rockchip/rockchip_pdm.c b/sound/soc/rockchip/rockchip_pdm.c index 400e29edb1c9..8a2e3bbce3a1 100644 --- a/sound/soc/rockchip/rockchip_pdm.c +++ b/sound/soc/rockchip/rockchip_pdm.c @@ -208,7 +208,9 @@ static int rockchip_pdm_set_fmt(struct snd_soc_dai *cpu_dai, return -EINVAL; } + pm_runtime_get_sync(cpu_dai->dev); regmap_update_bits(pdm->regmap, PDM_CLK_CTRL, mask, val); + pm_runtime_put(cpu_dai->dev); return 0; } -- cgit v1.2.3-59-g8ed1b From 86a7b6ffd90095d81d9fa0d8b48955b7c83b2e2f Mon Sep 17 00:00:00 2001 From: Sugar Zhang Date: Thu, 4 Apr 2019 11:48:11 +0800 Subject: ASoC: rockchip: pdm: change dma burst to 8 This patch decreases the transfer bursts to avoid the fifo overrun. Signed-off-by: Sugar Zhang Signed-off-by: Mark Brown --- sound/soc/rockchip/rockchip_pdm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/rockchip/rockchip_pdm.c b/sound/soc/rockchip/rockchip_pdm.c index 8a2e3bbce3a1..d0b403a0e27b 100644 --- a/sound/soc/rockchip/rockchip_pdm.c +++ b/sound/soc/rockchip/rockchip_pdm.c @@ -24,7 +24,7 @@ #include "rockchip_pdm.h" -#define PDM_DMA_BURST_SIZE (16) /* size * width: 16*4 = 64 bytes */ +#define PDM_DMA_BURST_SIZE (8) /* size * width: 8*4 = 32 bytes */ struct rk_pdm_dev { struct device *dev; -- cgit v1.2.3-59-g8ed1b From 47c4cc08cb5b34e93ab337b924c5ede77ca3c936 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 4 Apr 2019 17:27:20 +0100 Subject: ASoC: cs35l35: Disable regulators on driver removal The chips main power supplies VA and VP are enabled during probe but then never disabled, this will cause warnings from the regulator framework on driver removal. Fix this by adding a remove callback and disabling the supplies, whilst doing so follow best practice and put the chip back into reset as well. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l35.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c index 9f4a59871cee..c71696146c5e 100644 --- a/sound/soc/codecs/cs35l35.c +++ b/sound/soc/codecs/cs35l35.c @@ -1635,6 +1635,16 @@ err: return ret; } +static int cs35l35_i2c_remove(struct i2c_client *i2c_client) +{ + struct cs35l35_private *cs35l35 = i2c_get_clientdata(i2c_client); + + regulator_bulk_disable(cs35l35->num_supplies, cs35l35->supplies); + gpiod_set_value_cansleep(cs35l35->reset_gpio, 0); + + return 0; +} + static const struct of_device_id cs35l35_of_match[] = { {.compatible = "cirrus,cs35l35"}, {}, @@ -1655,6 +1665,7 @@ static struct i2c_driver cs35l35_i2c_driver = { }, .id_table = cs35l35_id, .probe = cs35l35_i2c_probe, + .remove = cs35l35_i2c_remove, }; module_i2c_driver(cs35l35_i2c_driver); -- cgit v1.2.3-59-g8ed1b From 2e05ddd2c9f8000751d52fcf35b8318da46026bc Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 4 Apr 2019 17:30:39 -0700 Subject: ASoC: intel: skylake: add remove() callback for component driver Topology is not unloaded in the core during unregister_component() anymore. So, add the remove() callback that will unload the topology. Signed-off-by: Ranjani Sridharan Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-pcm.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 56099db8f86d..57031b6d4d45 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -1462,9 +1462,16 @@ static int skl_platform_soc_probe(struct snd_soc_component *component) return 0; } +static void skl_pcm_remove(struct snd_soc_component *component) +{ + /* remove topology */ + snd_soc_tplg_component_remove(component, SND_SOC_TPLG_INDEX_ALL); +} + static const struct snd_soc_component_driver skl_component = { .name = "pcm", .probe = skl_platform_soc_probe, + .remove = skl_pcm_remove, .ops = &skl_platform_ops, .pcm_new = skl_pcm_new, .pcm_free = skl_pcm_free, -- cgit v1.2.3-59-g8ed1b From 54f8844e3f6cf898450a6c85f70fa997f0aa72b9 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Thu, 4 Apr 2019 19:48:33 -0700 Subject: ASoC: topology: Use the correct dobj to free enum control values and texts The control values and texts of the enum kcontrol associated with a widget need to be freed when the widget is removed. However, both struct snd_soc_dapm_widget and struct soc_enum contain a dobj member, which resulted in a confusion. The existing code generates a null pointer dereference by attempting to free the values and texts from the dobj which belongs to the widget instead of the dobj belonging to the enum kcontrol. The suggested fix is to use the correct dobj member (se->dobj) of the enum kcontrol. Signed-off-by: Ranjani Sridharan Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 25fca7055464..96852d250619 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -482,10 +482,11 @@ static void remove_widget(struct snd_soc_component *comp, snd_ctl_remove(card, kcontrol); - kfree(dobj->control.dvalues); + /* free enum kcontrol's dvalues and dtexts */ + kfree(se->dobj.control.dvalues); for (j = 0; j < se->items; j++) - kfree(dobj->control.dtexts[j]); - kfree(dobj->control.dtexts); + kfree(se->dobj.control.dtexts[j]); + kfree(se->dobj.control.dtexts); kfree(se); kfree(w->kcontrol_news[i].name); -- cgit v1.2.3-59-g8ed1b From 17d3069ccf06970e2db3f7cbf4335f207524279e Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Fri, 5 Apr 2019 11:19:11 +0200 Subject: ASoC: stm32: fix sai driver name initialisation This patch fixes the sai driver structure overwriting which results in a cpu dai name equal NULL. Fixes: 3e086ed ("ASoC: stm32: add SAI driver") Signed-off-by: Arnaud Pouliquen Signed-off-by: Mark Brown --- sound/soc/stm/stm32_sai_sub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index 55d802f51c15..83d8a7ac56f4 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -1419,7 +1419,6 @@ static int stm32_sai_sub_dais_init(struct platform_device *pdev, if (!sai->cpu_dai_drv) return -ENOMEM; - sai->cpu_dai_drv->name = dev_name(&pdev->dev); if (STM_SAI_IS_PLAYBACK(sai)) { memcpy(sai->cpu_dai_drv, &stm32_sai_playback_dai, sizeof(stm32_sai_playback_dai)); @@ -1429,6 +1428,7 @@ static int stm32_sai_sub_dais_init(struct platform_device *pdev, sizeof(stm32_sai_capture_dai)); sai->cpu_dai_drv->capture.stream_name = sai->cpu_dai_drv->name; } + sai->cpu_dai_drv->name = dev_name(&pdev->dev); return 0; } -- cgit v1.2.3-59-g8ed1b From b4ed6b51f356224c6c71540ed94087f7f09b84af Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 5 Apr 2019 09:57:08 -0700 Subject: ASoC: core: conditionally increase module refcount on component open Recently, for Intel platforms the "ignore_module_refcount" field was introduced for the component driver. In order to avoid a deadlock preventing the PCI modules from being removed even when the card was idle, the refcounts were not incremented for the device driver module during component probe. However, this change introduced a nasty side effect: the device driver module can be unloaded while a pcm stream is open. This patch proposes to change the field to be renamed as "module_get_upon_open". When this field is set, the module refcount should be incremented on pcm open amd decremented upon pcm close. This will enable modules to be removed when no PCM playback/capture happens and prevent removal when the component is actually in use. Also, align with the skylake component driver with the new name. Fixes: b450b878('ASoC: core: don't increase component module refcount unconditionally' Signed-off-by: Ranjani Sridharan Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- include/sound/soc.h | 9 +++++++-- sound/soc/intel/skylake/skl-pcm.c | 2 +- sound/soc/soc-core.c | 4 ++-- 3 files changed, 10 insertions(+), 5 deletions(-) (limited to 'sound/soc') diff --git a/include/sound/soc.h b/include/sound/soc.h index 1e2be35ed36f..482b4ea87c3c 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -802,8 +802,13 @@ 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; + /* + * signal if the module handling the component should not be removed + * if a pcm is open. Setting this would prevent the module + * refcount being incremented in probe() but allow it be incremented + * when a pcm is opened and decremented when it is closed. + */ + unsigned int module_get_upon_open:1; /* bits */ unsigned int idle_bias_on:1; diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 57031b6d4d45..9735e2412251 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -1475,7 +1475,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 */ + .module_get_upon_open = 1, /* increment refcount when a pcm is opened */ }; int skl_platform_register(struct device *dev) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index d88757659729..46e3ab0fced4 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -947,7 +947,7 @@ 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; - if (!component->driver->ignore_module_refcount) + if (!component->driver->module_get_upon_open) module_put(component->dev->driver->owner); } @@ -1381,7 +1381,7 @@ static int soc_probe_component(struct snd_soc_card *card, return 0; } - if (!component->driver->ignore_module_refcount && + if (!component->driver->module_get_upon_open && !try_module_get(component->dev->driver->owner)) return -ENODEV; -- cgit v1.2.3-59-g8ed1b From 52034add758e268c39110f33d46e2a9492e82aef Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 5 Apr 2019 09:57:09 -0700 Subject: ASoC: pcm: update module refcount if module_get_upon_open is set Setting the module_get_upon_open field for component driver prevents the module refcount from being incremented during component probe(). This could lead to the module being allowed to be unloaded when a pcm stream is open. So, if this field is set, the module's refcount should be incremented during pcm open to prevent module removal when the component is in use. And, the refcount should be decremented upon pcm close. Signed-off-by: Ranjani Sridharan Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'sound/soc') diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 2d5d5cac4ba6..d21247546f7f 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -463,6 +464,9 @@ static int soc_pcm_components_close(struct snd_pcm_substream *substream, continue; component->driver->ops->close(substream); + + if (component->driver->module_get_upon_open) + module_put(component->dev->driver->owner); } return 0; @@ -513,6 +517,10 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) !component->driver->ops->open) continue; + if (component->driver->module_get_upon_open && + !try_module_get(component->dev->driver->owner)) + return -ENODEV; + ret = component->driver->ops->open(substream); if (ret < 0) { dev_err(component->dev, -- cgit v1.2.3-59-g8ed1b From d6ba3f815bc5f3c4249d15c8bc5fbb012651b4a4 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Mon, 8 Apr 2019 17:08:58 +0800 Subject: ASoC: Intel: kbl: fix wrong number of channels Fix wrong setting on number of channels. The context wants to set constraint to 2 channels instead of 4. Signed-off-by: Tzung-Bi Shih Acked-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc') diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c index 7044d8c2b187..879f14257a3e 100644 --- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c +++ b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c @@ -405,7 +405,7 @@ static const struct snd_pcm_hw_constraint_list constraints_dmic_channels = { }; static const unsigned int dmic_2ch[] = { - 4, + 2, }; static const struct snd_pcm_hw_constraint_list constraints_dmic_2ch = { -- cgit v1.2.3-59-g8ed1b From e37c2deafe7058cf7989c4c47bbf1140cc867d89 Mon Sep 17 00:00:00 2001 From: Olivier Moysan Date: Wed, 10 Apr 2019 10:08:36 +0200 Subject: ASoC: stm32: sai: fix master clock management When master clock is used, master clock rate is set exclusively. Parent clocks of master clock cannot be changed after a call to clk_set_rate_exclusive(). So the parent clock of SAI kernel clock must be set before. Ensure also that exclusive rate operations are balanced in STM32 SAI driver. Signed-off-by: Olivier Moysan Signed-off-by: Mark Brown --- sound/soc/stm/stm32_sai_sub.c | 64 +++++++++++++++++++++++++++++++------------ 1 file changed, 47 insertions(+), 17 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index 83d8a7ac56f4..d7045aa520de 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -70,6 +70,7 @@ #define SAI_IEC60958_STATUS_BYTES 24 #define SAI_MCLK_NAME_LEN 32 +#define SAI_RATE_11K 11025 /** * struct stm32_sai_sub_data - private data of SAI sub block (block A or B) @@ -309,6 +310,25 @@ static int stm32_sai_set_clk_div(struct stm32_sai_sub_data *sai, return ret; } +static int stm32_sai_set_parent_clock(struct stm32_sai_sub_data *sai, + unsigned int rate) +{ + struct platform_device *pdev = sai->pdev; + struct clk *parent_clk = sai->pdata->clk_x8k; + int ret; + + if (!(rate % SAI_RATE_11K)) + parent_clk = sai->pdata->clk_x11k; + + ret = clk_set_parent(sai->sai_ck, parent_clk); + if (ret) + dev_err(&pdev->dev, " Error %d setting sai_ck parent clock. %s", + ret, ret == -EBUSY ? + "Active stream rates conflict\n" : "\n"); + + return ret; +} + static long stm32_sai_mclk_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *prate) { @@ -490,25 +510,29 @@ static int stm32_sai_set_sysclk(struct snd_soc_dai *cpu_dai, struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai); int ret; - if (dir == SND_SOC_CLOCK_OUT) { + if (dir == SND_SOC_CLOCK_OUT && sai->sai_mclk) { ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, SAI_XCR1_NODIV, (unsigned int)~SAI_XCR1_NODIV); if (ret < 0) return ret; - dev_dbg(cpu_dai->dev, "SAI MCLK frequency is %uHz\n", freq); - sai->mclk_rate = freq; + /* If master clock is used, set parent clock now */ + ret = stm32_sai_set_parent_clock(sai, freq); + if (ret) + return ret; - if (sai->sai_mclk) { - ret = clk_set_rate_exclusive(sai->sai_mclk, - sai->mclk_rate); - if (ret) { - dev_err(cpu_dai->dev, - "Could not set mclk rate\n"); - return ret; - } + ret = clk_set_rate_exclusive(sai->sai_mclk, freq); + if (ret) { + dev_err(cpu_dai->dev, + ret == -EBUSY ? + "Active streams have incompatible rates" : + "Could not set mclk rate\n"); + return ret; } + + dev_dbg(cpu_dai->dev, "SAI MCLK frequency is %uHz\n", freq); + sai->mclk_rate = freq; } return 0; @@ -916,11 +940,13 @@ static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai, int div = 0, cr1 = 0; int sai_clk_rate, mclk_ratio, den; unsigned int rate = params_rate(params); + int ret; - if (!(rate % 11025)) - clk_set_parent(sai->sai_ck, sai->pdata->clk_x11k); - else - clk_set_parent(sai->sai_ck, sai->pdata->clk_x8k); + if (!sai->sai_mclk) { + ret = stm32_sai_set_parent_clock(sai, rate); + if (ret) + return ret; + } sai_clk_rate = clk_get_rate(sai->sai_ck); if (STM_SAI_IS_F4(sai->pdata)) { @@ -1079,9 +1105,13 @@ static void stm32_sai_shutdown(struct snd_pcm_substream *substream, regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, SAI_XCR1_NODIV, SAI_XCR1_NODIV); - clk_disable_unprepare(sai->sai_ck); + /* Release mclk rate only if rate was actually set */ + if (sai->mclk_rate) { + clk_rate_exclusive_put(sai->sai_mclk); + sai->mclk_rate = 0; + } - clk_rate_exclusive_put(sai->sai_mclk); + clk_disable_unprepare(sai->sai_ck); spin_lock_irqsave(&sai->irq_lock, flags); sai->substream = NULL; -- cgit v1.2.3-59-g8ed1b From 70802487bb9145a4f8b26f5a11d0e7f83c25100a Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Mon, 8 Apr 2019 12:30:25 -0700 Subject: ASoC: pcm: fix error handling when try_module_get() fails. Handle error before returning when try_module_get() fails to prevent inconsistent mutex lock/unlock. Fixes: 52034add7 (ASoC: pcm: update module refcount if module_get_upon_open is set) Signed-off-by: Ranjani Sridharan Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'sound/soc') diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index d21247546f7f..be80a12fba27 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -518,8 +518,10 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) continue; if (component->driver->module_get_upon_open && - !try_module_get(component->dev->driver->owner)) - return -ENODEV; + !try_module_get(component->dev->driver->owner)) { + ret = -ENODEV; + goto module_err; + } ret = component->driver->ops->open(substream); if (ret < 0) { @@ -636,7 +638,7 @@ codec_dai_err: component_err: soc_pcm_components_close(substream, component); - +module_err: if (cpu_dai->driver->ops->shutdown) cpu_dai->driver->ops->shutdown(substream, cpu_dai); out: -- cgit v1.2.3-59-g8ed1b From ac71317e6be01812cc0c54d8be6d3c1139c8380b Mon Sep 17 00:00:00 2001 From: Marc Gonzalez Date: Wed, 10 Apr 2019 16:23:38 +0200 Subject: ASoC: wcd9335: Fix missing regmap requirement wcd9335.c: undefined reference to 'devm_regmap_add_irq_chip' Signed-off-by: Marc Gonzalez Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/soc') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 419114edfd57..667fc1d59e18 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1151,6 +1151,7 @@ config SND_SOC_WCD9335 tristate "WCD9335 Codec" depends on SLIMBUS select REGMAP_SLIMBUS + select REGMAP_IRQ help The WCD9335 is a standalone Hi-Fi audio CODEC IC, supports Qualcomm Technologies, Inc. (QTI) multimedia solutions, -- cgit v1.2.3-59-g8ed1b