Commit 234d8f27 authored by Takashi Iwai's avatar Takashi Iwai

Merge tag 'asoc-fix-v5.14-rc2' of...

Merge tag 'asoc-fix-v5.14-rc2' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-linus

ASoC: Fixes for v5.14

A collection of fixes for ASoC that have come in since the merge window,
all driver specific.  There is a new core feature added for reversing
the order of operations when shutting down, this is needed to fix a bug
with the AMD Stonyridge platform, and we also tweak the Kconfig to make
the SSM2518 driver user selectable so it can be used with generic cards
but that requires no actual code changes.
parents e81d71e3 82d28b67
......@@ -114,7 +114,7 @@ properties:
ports:
$ref: /schemas/graph.yaml#/properties/ports
properties:
patternProperties:
port(@[0-9a-f]+)?:
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
......
......@@ -712,6 +712,12 @@ struct snd_soc_dai_link {
/* Do not create a PCM for this DAI link (Backend link) */
unsigned int ignore:1;
/* This flag will reorder stop sequence. By enabling this flag
* DMA controller stop sequence will be invoked first followed by
* CPU DAI driver stop sequence
*/
unsigned int stop_dma_first:1;
#ifdef CONFIG_SND_SOC_TOPOLOGY
struct snd_soc_dobj dobj; /* For topology */
#endif
......
......@@ -576,6 +576,7 @@ static struct snd_soc_dai_link cz_dai_5682_98357[] = {
| SND_SOC_DAIFMT_CBM_CFM,
.init = cz_rt5682_init,
.dpcm_playback = 1,
.stop_dma_first = 1,
.ops = &cz_rt5682_play_ops,
SND_SOC_DAILINK_REG(designware1, rt5682, platform),
},
......@@ -585,6 +586,7 @@ static struct snd_soc_dai_link cz_dai_5682_98357[] = {
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBM_CFM,
.dpcm_capture = 1,
.stop_dma_first = 1,
.ops = &cz_rt5682_cap_ops,
SND_SOC_DAILINK_REG(designware2, rt5682, platform),
},
......@@ -594,6 +596,7 @@ static struct snd_soc_dai_link cz_dai_5682_98357[] = {
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBM_CFM,
.dpcm_playback = 1,
.stop_dma_first = 1,
.ops = &cz_rt5682_max_play_ops,
SND_SOC_DAILINK_REG(designware3, mx, platform),
},
......@@ -604,6 +607,7 @@ static struct snd_soc_dai_link cz_dai_5682_98357[] = {
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBM_CFM,
.dpcm_capture = 1,
.stop_dma_first = 1,
.ops = &cz_rt5682_dmic0_cap_ops,
SND_SOC_DAILINK_REG(designware3, adau, platform),
},
......@@ -614,6 +618,7 @@ static struct snd_soc_dai_link cz_dai_5682_98357[] = {
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBM_CFM,
.dpcm_capture = 1,
.stop_dma_first = 1,
.ops = &cz_rt5682_dmic1_cap_ops,
SND_SOC_DAILINK_REG(designware2, adau, platform),
},
......
......@@ -1325,7 +1325,7 @@ config SND_SOC_SSM2305
high-efficiency mono Class-D audio power amplifiers.
config SND_SOC_SSM2518
tristate
tristate "Analog Devices SSM2518 Class-D Amplifier"
depends on I2C
config SND_SOC_SSM2602
......@@ -1557,6 +1557,7 @@ config SND_SOC_WCD934X
Qualcomm SoCs like SDM845.
config SND_SOC_WCD938X
depends on SND_SOC_WCD938X_SDW
tristate
config SND_SOC_WCD938X_SDW
......@@ -1813,11 +1814,6 @@ config SND_SOC_ZL38060
which consists of a Digital Signal Processor (DSP), several Digital
Audio Interfaces (DAIs), analog outputs, and a block of 14 GPIOs.
config SND_SOC_ZX_AUD96P22
tristate "ZTE ZX AUD96P22 CODEC"
depends on I2C
select REGMAP_I2C
# Amp
config SND_SOC_LM4857
tristate
......
......@@ -1695,6 +1695,8 @@ static const struct regmap_config rt5631_regmap_config = {
.reg_defaults = rt5631_reg,
.num_reg_defaults = ARRAY_SIZE(rt5631_reg),
.cache_type = REGCACHE_RBTREE,
.use_single_read = true,
.use_single_write = true,
};
static int rt5631_i2c_probe(struct i2c_client *i2c,
......
......@@ -973,10 +973,14 @@ int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert)
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);
if (!snd_soc_dapm_get_pin_status(dapm, "MICBIAS"))
if (!snd_soc_dapm_get_pin_status(dapm, "MICBIAS") &&
!snd_soc_dapm_get_pin_status(dapm, "PLL1") &&
!snd_soc_dapm_get_pin_status(dapm, "PLL2B"))
snd_soc_component_update_bits(component,
RT5682_PWR_ANLG_1, RT5682_PWR_MB, 0);
if (!snd_soc_dapm_get_pin_status(dapm, "Vref2"))
if (!snd_soc_dapm_get_pin_status(dapm, "Vref2") &&
!snd_soc_dapm_get_pin_status(dapm, "PLL1") &&
!snd_soc_dapm_get_pin_status(dapm, "PLL2B"))
snd_soc_component_update_bits(component,
RT5682_PWR_ANLG_1, RT5682_PWR_VREF2, 0);
snd_soc_component_update_bits(component, RT5682_PWR_ANLG_3,
......
......@@ -1604,6 +1604,8 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c,
ret);
return ret;
}
regcache_cache_only(aic31xx->regmap, true);
aic31xx->dev = &i2c->dev;
aic31xx->irq = i2c->irq;
......
......@@ -151,8 +151,8 @@ struct aic31xx_pdata {
#define AIC31XX_WORD_LEN_24BITS 0x02
#define AIC31XX_WORD_LEN_32BITS 0x03
#define AIC31XX_IFACE1_MASTER_MASK GENMASK(3, 2)
#define AIC31XX_BCLK_MASTER BIT(2)
#define AIC31XX_WCLK_MASTER BIT(3)
#define AIC31XX_BCLK_MASTER BIT(3)
#define AIC31XX_WCLK_MASTER BIT(2)
/* AIC31XX_DATA_OFFSET */
#define AIC31XX_DATA_OFFSET_MASK GENMASK(7, 0)
......
......@@ -250,8 +250,8 @@ static DECLARE_TLV_DB_SCALE(tlv_pcm, -6350, 50, 0);
static DECLARE_TLV_DB_SCALE(tlv_driver_gain, -600, 100, 0);
/* -12dB min, 0.5dB steps */
static DECLARE_TLV_DB_SCALE(tlv_adc_vol, -1200, 50, 0);
static DECLARE_TLV_DB_LINEAR(tlv_spk_vol, TLV_DB_GAIN_MUTE, 0);
/* -6dB min, 1dB steps */
static DECLARE_TLV_DB_SCALE(tlv_tas_driver_gain, -5850, 50, 0);
static DECLARE_TLV_DB_SCALE(tlv_amp_vol, 0, 600, 1);
static const char * const lo_cm_text[] = {
......@@ -1063,21 +1063,20 @@ static const struct snd_soc_component_driver soc_component_dev_aic32x4 = {
};
static const struct snd_kcontrol_new aic32x4_tas2505_snd_controls[] = {
SOC_DOUBLE_R_S_TLV("PCM Playback Volume", AIC32X4_LDACVOL,
AIC32X4_LDACVOL, 0, -0x7f, 0x30, 7, 0, tlv_pcm),
SOC_SINGLE_S8_TLV("PCM Playback Volume",
AIC32X4_LDACVOL, -0x7f, 0x30, tlv_pcm),
SOC_ENUM("DAC Playback PowerTune Switch", l_ptm_enum),
SOC_DOUBLE_R_S_TLV("HP Driver Playback Volume", AIC32X4_HPLGAIN,
AIC32X4_HPLGAIN, 0, -0x6, 0x1d, 5, 0,
tlv_driver_gain),
SOC_DOUBLE_R("HP DAC Playback Switch", AIC32X4_HPLGAIN,
AIC32X4_HPLGAIN, 6, 0x01, 1),
SOC_SINGLE("Auto-mute Switch", AIC32X4_DACMUTE, 4, 7, 0),
SOC_SINGLE_TLV("HP Driver Gain Volume",
AIC32X4_HPLGAIN, 0, 0x74, 1, tlv_tas_driver_gain),
SOC_SINGLE("HP DAC Playback Switch", AIC32X4_HPLGAIN, 6, 1, 1),
SOC_SINGLE_RANGE_TLV("Speaker Driver Playback Volume", TAS2505_SPKVOL1,
0, 0, 117, 1, tlv_spk_vol),
SOC_SINGLE_TLV("Speaker Amplifier Playback Volume", TAS2505_SPKVOL2,
4, 5, 0, tlv_amp_vol),
SOC_SINGLE_TLV("Speaker Driver Playback Volume",
TAS2505_SPKVOL1, 0, 0x74, 1, tlv_tas_driver_gain),
SOC_SINGLE_TLV("Speaker Amplifier Playback Volume",
TAS2505_SPKVOL2, 4, 5, 0, tlv_amp_vol),
SOC_SINGLE("Auto-mute Switch", AIC32X4_DACMUTE, 4, 7, 0),
};
static const struct snd_kcontrol_new hp_output_mixer_controls[] = {
......
......@@ -3317,13 +3317,6 @@ static int wcd938x_soc_codec_probe(struct snd_soc_component *component)
(WCD938X_DIGITAL_INTR_LEVEL_0 + i), 0);
}
ret = wcd938x_irq_init(wcd938x, component->dev);
if (ret) {
dev_err(component->dev, "%s: IRQ init failed: %d\n",
__func__, ret);
return ret;
}
wcd938x->hphr_pdm_wd_int = regmap_irq_get_virq(wcd938x->irq_chip,
WCD938X_IRQ_HPHR_PDM_WD_INT);
wcd938x->hphl_pdm_wd_int = regmap_irq_get_virq(wcd938x->irq_chip,
......@@ -3553,7 +3546,6 @@ static int wcd938x_bind(struct device *dev)
}
wcd938x->sdw_priv[AIF1_PB] = dev_get_drvdata(wcd938x->rxdev);
wcd938x->sdw_priv[AIF1_PB]->wcd938x = wcd938x;
wcd938x->sdw_priv[AIF1_PB]->slave_irq = wcd938x->virq;
wcd938x->txdev = wcd938x_sdw_device_get(wcd938x->txnode);
if (!wcd938x->txdev) {
......@@ -3562,7 +3554,6 @@ static int wcd938x_bind(struct device *dev)
}
wcd938x->sdw_priv[AIF1_CAP] = dev_get_drvdata(wcd938x->txdev);
wcd938x->sdw_priv[AIF1_CAP]->wcd938x = wcd938x;
wcd938x->sdw_priv[AIF1_CAP]->slave_irq = wcd938x->virq;
wcd938x->tx_sdw_dev = dev_to_sdw_dev(wcd938x->txdev);
if (!wcd938x->tx_sdw_dev) {
dev_err(dev, "could not get txslave with matching of dev\n");
......@@ -3595,6 +3586,15 @@ static int wcd938x_bind(struct device *dev)
return PTR_ERR(wcd938x->regmap);
}
ret = wcd938x_irq_init(wcd938x, dev);
if (ret) {
dev_err(dev, "%s: IRQ init failed: %d\n", __func__, ret);
return ret;
}
wcd938x->sdw_priv[AIF1_PB]->slave_irq = wcd938x->virq;
wcd938x->sdw_priv[AIF1_CAP]->slave_irq = wcd938x->virq;
ret = wcd938x_set_micbias_data(wcd938x);
if (ret < 0) {
dev_err(dev, "%s: bad micbias pdata\n", __func__);
......
......@@ -282,6 +282,7 @@
/*
* HALO_CCM_CORE_CONTROL
*/
#define HALO_CORE_RESET 0x00000200
#define HALO_CORE_EN 0x00000001
/*
......@@ -1213,7 +1214,7 @@ static int wm_coeff_tlv_get(struct snd_kcontrol *kctl,
mutex_lock(&ctl->dsp->pwr_lock);
ret = wm_coeff_read_ctrl_raw(ctl, ctl->cache, size);
ret = wm_coeff_read_ctrl(ctl, ctl->cache, size);
if (!ret && copy_to_user(bytes, ctl->cache, size))
ret = -EFAULT;
......@@ -3333,7 +3334,8 @@ static int wm_halo_start_core(struct wm_adsp *dsp)
{
return regmap_update_bits(dsp->regmap,
dsp->base + HALO_CCM_CORE_CONTROL,
HALO_CORE_EN, HALO_CORE_EN);
HALO_CORE_RESET | HALO_CORE_EN,
HALO_CORE_RESET | HALO_CORE_EN);
}
static void wm_halo_stop_core(struct wm_adsp *dsp)
......
......@@ -55,43 +55,68 @@ static int spk_init(struct snd_soc_pcm_runtime *rtd)
return ret;
}
static int max98373_sdw_trigger(struct snd_pcm_substream *substream, int cmd)
static int mx8373_enable_spk_pin(struct snd_pcm_substream *substream, bool enable)
{
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_soc_dai *codec_dai;
struct snd_soc_dai *cpu_dai;
int ret;
int j;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
/* enable max98373 first */
ret = max_98373_trigger(substream, cmd);
if (ret < 0)
break;
ret = sdw_trigger(substream, cmd);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
ret = sdw_trigger(substream, cmd);
if (ret < 0)
break;
ret = max_98373_trigger(substream, cmd);
break;
default:
ret = -EINVAL;
break;
/* set spk pin by playback only */
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
return 0;
cpu_dai = asoc_rtd_to_cpu(rtd, 0);
for_each_rtd_codec_dais(rtd, j, codec_dai) {
struct snd_soc_dapm_context *dapm =
snd_soc_component_get_dapm(cpu_dai->component);
char pin_name[16];
snprintf(pin_name, ARRAY_SIZE(pin_name), "%s Spk",
codec_dai->component->name_prefix);
if (enable)
ret = snd_soc_dapm_enable_pin(dapm, pin_name);
else
ret = snd_soc_dapm_disable_pin(dapm, pin_name);
if (!ret)
snd_soc_dapm_sync(dapm);
}
return ret;
return 0;
}
static int mx8373_sdw_prepare(struct snd_pcm_substream *substream)
{
int ret = 0;
/* according to soc_pcm_prepare dai link prepare is called first */
ret = sdw_prepare(substream);
if (ret < 0)
return ret;
return mx8373_enable_spk_pin(substream, true);
}
static int mx8373_sdw_hw_free(struct snd_pcm_substream *substream)
{
int ret = 0;
/* according to soc_pcm_hw_free dai link free is called first */
ret = sdw_hw_free(substream);
if (ret < 0)
return ret;
return mx8373_enable_spk_pin(substream, false);
}
static const struct snd_soc_ops max_98373_sdw_ops = {
.startup = sdw_startup,
.prepare = sdw_prepare,
.trigger = max98373_sdw_trigger,
.hw_free = sdw_hw_free,
.prepare = mx8373_sdw_prepare,
.trigger = sdw_trigger,
.hw_free = mx8373_sdw_hw_free,
.shutdown = sdw_shutdown,
};
......
......@@ -1015,6 +1015,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
int ret = -EINVAL, _ret = 0;
int rollback = 0;
......@@ -1055,14 +1056,23 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
ret = snd_soc_pcm_dai_trigger(substream, cmd, rollback);
if (ret < 0)
break;
if (rtd->dai_link->stop_dma_first) {
ret = snd_soc_pcm_component_trigger(substream, cmd, rollback);
if (ret < 0)
break;
ret = snd_soc_pcm_component_trigger(substream, cmd, rollback);
if (ret < 0)
break;
ret = snd_soc_pcm_dai_trigger(substream, cmd, rollback);
if (ret < 0)
break;
} else {
ret = snd_soc_pcm_dai_trigger(substream, cmd, rollback);
if (ret < 0)
break;
ret = snd_soc_pcm_component_trigger(substream, cmd, rollback);
if (ret < 0)
break;
}
ret = snd_soc_link_trigger(substream, cmd, rollback);
break;
}
......
......@@ -89,6 +89,7 @@ static const struct sof_dev_desc adls_desc = {
static const struct sof_dev_desc adl_desc = {
.machines = snd_soc_acpi_intel_adl_machines,
.alt_machines = snd_soc_acpi_intel_adl_sdw_machines,
.use_acpi_target_states = true,
.resindex_lpe_base = 0,
.resindex_pcicfg_base = -1,
.resindex_imr_base = -1,
......
......@@ -213,19 +213,19 @@ snd_pcm_uframes_t tegra_pcm_pointer(struct snd_soc_component *component,
}
EXPORT_SYMBOL_GPL(tegra_pcm_pointer);
static int tegra_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream,
static int tegra_pcm_preallocate_dma_buffer(struct device *dev, struct snd_pcm *pcm, int stream,
size_t size)
{
struct snd_pcm_substream *substream = pcm->streams[stream].substream;
struct snd_dma_buffer *buf = &substream->dma_buffer;
buf->area = dma_alloc_wc(pcm->card->dev, size, &buf->addr, GFP_KERNEL);
buf->area = dma_alloc_wc(dev, size, &buf->addr, GFP_KERNEL);
if (!buf->area)
return -ENOMEM;
buf->private_data = NULL;
buf->dev.type = SNDRV_DMA_TYPE_DEV;
buf->dev.dev = pcm->card->dev;
buf->dev.dev = dev;
buf->bytes = size;
return 0;
......@@ -244,31 +244,28 @@ static void tegra_pcm_deallocate_dma_buffer(struct snd_pcm *pcm, int stream)
if (!buf->area)
return;
dma_free_wc(pcm->card->dev, buf->bytes, buf->area, buf->addr);
dma_free_wc(buf->dev.dev, buf->bytes, buf->area, buf->addr);
buf->area = NULL;
}
static int tegra_pcm_dma_allocate(struct snd_soc_pcm_runtime *rtd,
static int tegra_pcm_dma_allocate(struct device *dev, struct snd_soc_pcm_runtime *rtd,
size_t size)
{
struct snd_card *card = rtd->card->snd_card;
struct snd_pcm *pcm = rtd->pcm;
int ret;
ret = dma_set_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
if (ret < 0)
return ret;
if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
ret = tegra_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_PLAYBACK, size);
ret = tegra_pcm_preallocate_dma_buffer(dev, pcm, SNDRV_PCM_STREAM_PLAYBACK, size);
if (ret)
goto err;
}
if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
ret = tegra_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_CAPTURE, size);
ret = tegra_pcm_preallocate_dma_buffer(dev, pcm, SNDRV_PCM_STREAM_CAPTURE, size);
if (ret)
goto err_free_play;
}
......@@ -284,7 +281,16 @@ static int tegra_pcm_dma_allocate(struct snd_soc_pcm_runtime *rtd,
int tegra_pcm_construct(struct snd_soc_component *component,
struct snd_soc_pcm_runtime *rtd)
{
return tegra_pcm_dma_allocate(rtd, tegra_pcm_hardware.buffer_bytes_max);
struct device *dev = component->dev;
/*
* Fallback for backwards-compatibility with older device trees that
* have the iommus property in the virtual, top-level "sound" node.
*/
if (!of_get_property(dev->of_node, "iommus", NULL))
dev = rtd->card->snd_card->dev;
return tegra_pcm_dma_allocate(dev, rtd, tegra_pcm_hardware.buffer_bytes_max);
}
EXPORT_SYMBOL_GPL(tegra_pcm_construct);
......
......@@ -197,7 +197,7 @@ static int j721e_configure_refclk(struct j721e_priv *priv,
return ret;
}
if (priv->hsdiv_rates[domain->parent_clk_id] != scki) {
if (domain->parent_clk_id == -1 || priv->hsdiv_rates[domain->parent_clk_id] != scki) {
dev_dbg(priv->dev,
"%s configuration for %u Hz: %s, %dxFS (SCKI: %u Hz)\n",
audio_domain == J721E_AUDIO_DOMAIN_CPB ? "CPB" : "IVI",
......@@ -278,23 +278,29 @@ static int j721e_audio_startup(struct snd_pcm_substream *substream)
j721e_rule_rate, &priv->rate_range,
SNDRV_PCM_HW_PARAM_RATE, -1);
mutex_unlock(&priv->mutex);
if (ret)
return ret;
goto out;
/* Reset TDM slots to 32 */
ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 0x3, 2, 32);
if (ret && ret != -ENOTSUPP)
return ret;
goto out;
for_each_rtd_codec_dais(rtd, i, codec_dai) {
ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x3, 0x3, 2, 32);
if (ret && ret != -ENOTSUPP)
return ret;
goto out;
}
return 0;
if (ret == -ENOTSUPP)
ret = 0;
out:
if (ret)
domain->active--;
mutex_unlock(&priv->mutex);
return ret;
}
static int j721e_audio_hw_params(struct snd_pcm_substream *substream,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment