ASoC: Fixes for v6.4

A collection of fixes for v6.4, mostly driver specific but there's also
 one fix for DPCM to avoid incorrectly repeated calls to prepare() which
 can trigger issues on some systems.
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCgAdFiEEreZoqmdXGLWf4p/qJNaLcl1Uh9AFAmRt4skACgkQJNaLcl1U
 h9Cl2gf8CnINVsSuzSgRqvpaxSpsEufghFJrlVtNPJxJz6z+1X+sz/bsq3ceuIWl
 56kJ9V0FgdcFJn8PtzJWSMvY/iwyMjAVrCl7cPqPlEIRrelQUihEteDQiL+lGrPn
 m0zkFWywW+r+KuzgoEosqL6/cDx7iR2NsELm/z/6aobsJRwVii7DigGAym9TNvwf
 dKvxy3uSX+XbCR7BTadO4wn4iHZ0/BkgYxUu4KckTgFDqHQHwrnbZNLhr0w214el
 bQuQOD0o6n8ZhBabOYv6j+TpwMO9qI/PjqJtn+fOZRi4pSmF1HlHL+8HLbukzblA
 FcsQJdXyKNzEbgHKTamOul9hgx4q4w==
 =H2J9
 -----END PGP SIGNATURE-----

Merge tag 'asoc-fix-v6.4-rc3' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-linus

ASoC: Fixes for v6.4

A collection of fixes for v6.4, mostly driver specific but there's also
one fix for DPCM to avoid incorrectly repeated calls to prepare() which
can trigger issues on some systems.
This commit is contained in:
Takashi Iwai 2023-05-24 12:14:24 +02:00
commit bac4d8220b
20 changed files with 101 additions and 59 deletions

View File

@ -8,7 +8,7 @@ Required properties:
"ti,tlv320aic32x6" TLV320AIC3206, TLV320AIC3256
"ti,tas2505" TAS2505, TAS2521
- reg: I2C slave address
- supply-*: Required supply regulators are:
- *-supply: Required supply regulators are:
"iov" - digital IO power supply
"ldoin" - LDO power supply
"dv" - Digital core power supply

View File

@ -170,6 +170,7 @@ struct snd_soc_acpi_link_adr {
/* Descriptor for SST ASoC machine driver */
struct snd_soc_acpi_mach {
u8 id[ACPI_ID_LEN];
const char *uid;
const struct snd_soc_acpi_codecs *comp_ids;
const u32 link_mask;
const struct snd_soc_acpi_link_adr *links;

View File

@ -122,6 +122,10 @@ int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe,
int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe,
struct snd_soc_pcm_runtime *be, int stream);
/* can this BE perform prepare */
int snd_soc_dpcm_can_be_prepared(struct snd_soc_pcm_runtime *fe,
struct snd_soc_pcm_runtime *be, int stream);
/* is the current PCM operation for this FE ? */
int snd_soc_dpcm_fe_can_update(struct snd_soc_pcm_runtime *fe, int stream);

View File

@ -66,7 +66,8 @@ enum skl_ch_cfg {
SKL_CH_CFG_DUAL_MONO = 9,
SKL_CH_CFG_I2S_DUAL_STEREO_0 = 10,
SKL_CH_CFG_I2S_DUAL_STEREO_1 = 11,
SKL_CH_CFG_4_CHANNEL = 12,
SKL_CH_CFG_7_1 = 12,
SKL_CH_CFG_4_CHANNEL = SKL_CH_CFG_7_1,
SKL_CH_CFG_INVALID
};

View File

@ -46,7 +46,7 @@ static const struct reg_default cs35l41_reg[] = {
{ CS35L41_DSP1_RX5_SRC, 0x00000020 },
{ CS35L41_DSP1_RX6_SRC, 0x00000021 },
{ CS35L41_DSP1_RX7_SRC, 0x0000003A },
{ CS35L41_DSP1_RX8_SRC, 0x00000001 },
{ CS35L41_DSP1_RX8_SRC, 0x0000003B },
{ CS35L41_NGATE1_SRC, 0x00000008 },
{ CS35L41_NGATE2_SRC, 0x00000009 },
{ CS35L41_AMP_DIG_VOL_CTRL, 0x00008000 },
@ -58,8 +58,8 @@ static const struct reg_default cs35l41_reg[] = {
{ CS35L41_IRQ1_MASK2, 0xFFFFFFFF },
{ CS35L41_IRQ1_MASK3, 0xFFFF87FF },
{ CS35L41_IRQ1_MASK4, 0xFEFFFFFF },
{ CS35L41_GPIO1_CTRL1, 0xE1000001 },
{ CS35L41_GPIO2_CTRL1, 0xE1000001 },
{ CS35L41_GPIO1_CTRL1, 0x81000001 },
{ CS35L41_GPIO2_CTRL1, 0x81000001 },
{ CS35L41_MIXER_NGATE_CFG, 0x00000000 },
{ CS35L41_MIXER_NGATE_CH1_CFG, 0x00000303 },
{ CS35L41_MIXER_NGATE_CH2_CFG, 0x00000303 },

View File

@ -746,6 +746,8 @@ static int tx_macro_put_dec_enum(struct snd_kcontrol *kcontrol,
struct tx_macro *tx = snd_soc_component_get_drvdata(component);
val = ucontrol->value.enumerated.item[0];
if (val >= e->items)
return -EINVAL;
switch (e->reg) {
case CDC_TX_INP_MUX_ADC_MUX0_CFG0:
@ -772,6 +774,9 @@ static int tx_macro_put_dec_enum(struct snd_kcontrol *kcontrol,
case CDC_TX_INP_MUX_ADC_MUX7_CFG0:
mic_sel_reg = CDC_TX7_TX_PATH_CFG0;
break;
default:
dev_err(component->dev, "Error in configuration!!\n");
return -EINVAL;
}
if (val != 0) {

View File

@ -267,7 +267,9 @@ static int rt5682_i2c_probe(struct i2c_client *i2c)
ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL,
rt5682_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
| IRQF_ONESHOT, "rt5682", rt5682);
if (ret)
if (!ret)
rt5682->irq = i2c->irq;
else
dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret);
}

View File

@ -2959,6 +2959,9 @@ static int rt5682_suspend(struct snd_soc_component *component)
if (rt5682->is_sdw)
return 0;
if (rt5682->irq)
disable_irq(rt5682->irq);
cancel_delayed_work_sync(&rt5682->jack_detect_work);
cancel_delayed_work_sync(&rt5682->jd_check_work);
if (rt5682->hs_jack && (rt5682->jack_type & SND_JACK_HEADSET) == SND_JACK_HEADSET) {
@ -3027,6 +3030,9 @@ static int rt5682_resume(struct snd_soc_component *component)
mod_delayed_work(system_power_efficient_wq,
&rt5682->jack_detect_work, msecs_to_jiffies(0));
if (rt5682->irq)
enable_irq(rt5682->irq);
return 0;
}
#else

View File

@ -1462,6 +1462,7 @@ struct rt5682_priv {
int pll_out[RT5682_PLLS];
int jack_type;
int irq;
int irq_work_delay_time;
};

View File

@ -183,30 +183,6 @@ static void i2s_stop(struct dw_i2s_dev *dev,
}
}
static int dw_i2s_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai)
{
struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
union dw_i2s_snd_dma_data *dma_data = NULL;
if (!(dev->capability & DWC_I2S_RECORD) &&
(substream->stream == SNDRV_PCM_STREAM_CAPTURE))
return -EINVAL;
if (!(dev->capability & DWC_I2S_PLAY) &&
(substream->stream == SNDRV_PCM_STREAM_PLAYBACK))
return -EINVAL;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
dma_data = &dev->play_dma_data;
else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
dma_data = &dev->capture_dma_data;
snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)dma_data);
return 0;
}
static void dw_i2s_config(struct dw_i2s_dev *dev, int stream)
{
u32 ch_reg;
@ -305,12 +281,6 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream,
return 0;
}
static void dw_i2s_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
snd_soc_dai_set_dma_data(dai, substream, NULL);
}
static int dw_i2s_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
@ -382,8 +352,6 @@ static int dw_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
}
static const struct snd_soc_dai_ops dw_i2s_dai_ops = {
.startup = dw_i2s_startup,
.shutdown = dw_i2s_shutdown,
.hw_params = dw_i2s_hw_params,
.prepare = dw_i2s_prepare,
.trigger = dw_i2s_trigger,
@ -625,6 +593,14 @@ static int dw_configure_dai_by_dt(struct dw_i2s_dev *dev,
}
static int dw_i2s_dai_probe(struct snd_soc_dai *dai)
{
struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
snd_soc_dai_init_dma_data(dai, &dev->play_dma_data, &dev->capture_dma_data);
return 0;
}
static int dw_i2s_probe(struct platform_device *pdev)
{
const struct i2s_platform_data *pdata = pdev->dev.platform_data;
@ -643,6 +619,7 @@ static int dw_i2s_probe(struct platform_device *pdev)
return -ENOMEM;
dw_i2s_dai->ops = &dw_i2s_dai_ops;
dw_i2s_dai->probe = dw_i2s_dai_probe;
dev->i2s_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(dev->i2s_base))

View File

@ -169,6 +169,7 @@ static bool apl_lp_streaming(struct avs_dev *adev)
{
struct avs_path *path;
spin_lock(&adev->path_list_lock);
/* Any gateway without buffer allocated in LP area disqualifies D0IX. */
list_for_each_entry(path, &adev->path_list, node) {
struct avs_path_pipeline *ppl;
@ -188,11 +189,14 @@ static bool apl_lp_streaming(struct avs_dev *adev)
if (cfg->copier.dma_type == INVALID_OBJECT_ID)
continue;
if (!mod->gtw_attrs.lp_buffer_alloc)
if (!mod->gtw_attrs.lp_buffer_alloc) {
spin_unlock(&adev->path_list_lock);
return false;
}
}
}
}
spin_unlock(&adev->path_list_lock);
return true;
}

View File

@ -283,8 +283,8 @@ void avs_release_firmwares(struct avs_dev *adev);
int avs_dsp_init_module(struct avs_dev *adev, u16 module_id, u8 ppl_instance_id,
u8 core_id, u8 domain, void *param, u32 param_size,
u16 *instance_id);
void avs_dsp_delete_module(struct avs_dev *adev, u16 module_id, u16 instance_id,
u8 *instance_id);
void avs_dsp_delete_module(struct avs_dev *adev, u16 module_id, u8 instance_id,
u8 ppl_instance_id, u8 core_id);
int avs_dsp_create_pipeline(struct avs_dev *adev, u16 req_size, u8 priority,
bool lp, u16 attributes, u8 *instance_id);

View File

@ -443,7 +443,7 @@ static int avs_register_i2s_boards(struct avs_dev *adev)
}
for (mach = boards->machs; mach->id[0]; mach++) {
if (!acpi_dev_present(mach->id, NULL, -1))
if (!acpi_dev_present(mach->id, mach->uid, -1))
continue;
if (mach->machine_quirk)

View File

@ -21,17 +21,25 @@ static struct avs_dev *avs_get_kcontrol_adev(struct snd_kcontrol *kcontrol)
return to_avs_dev(w->dapm->component->dev);
}
static struct avs_path_module *avs_get_kcontrol_module(struct avs_dev *adev, u32 id)
static struct avs_path_module *avs_get_volume_module(struct avs_dev *adev, u32 id)
{
struct avs_path *path;
struct avs_path_pipeline *ppl;
struct avs_path_module *mod;
list_for_each_entry(path, &adev->path_list, node)
list_for_each_entry(ppl, &path->ppl_list, node)
list_for_each_entry(mod, &ppl->mod_list, node)
if (mod->template->ctl_id && mod->template->ctl_id == id)
spin_lock(&adev->path_list_lock);
list_for_each_entry(path, &adev->path_list, node) {
list_for_each_entry(ppl, &path->ppl_list, node) {
list_for_each_entry(mod, &ppl->mod_list, node) {
if (guid_equal(&mod->template->cfg_ext->type, &AVS_PEAKVOL_MOD_UUID)
&& mod->template->ctl_id == id) {
spin_unlock(&adev->path_list_lock);
return mod;
}
}
}
}
spin_unlock(&adev->path_list_lock);
return NULL;
}
@ -49,7 +57,7 @@ int avs_control_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_va
/* prevent access to modules while path is being constructed */
mutex_lock(&adev->path_mutex);
active_module = avs_get_kcontrol_module(adev, ctl_data->id);
active_module = avs_get_volume_module(adev, ctl_data->id);
if (active_module) {
ret = avs_ipc_peakvol_get_volume(adev, active_module->module_id,
active_module->instance_id, &dspvols,
@ -89,7 +97,7 @@ int avs_control_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_va
changed = 1;
}
active_module = avs_get_kcontrol_module(adev, ctl_data->id);
active_module = avs_get_volume_module(adev, ctl_data->id);
if (active_module) {
dspvol.channel_id = AVS_ALL_CHANNELS_MASK;
dspvol.target_volume = *volume;

View File

@ -225,7 +225,7 @@ err:
int avs_dsp_init_module(struct avs_dev *adev, u16 module_id, u8 ppl_instance_id,
u8 core_id, u8 domain, void *param, u32 param_size,
u16 *instance_id)
u8 *instance_id)
{
struct avs_module_entry mentry;
bool was_loaded = false;
@ -272,7 +272,7 @@ err_mod_entry:
return ret;
}
void avs_dsp_delete_module(struct avs_dev *adev, u16 module_id, u16 instance_id,
void avs_dsp_delete_module(struct avs_dev *adev, u16 module_id, u8 instance_id,
u8 ppl_instance_id, u8 core_id)
{
struct avs_module_entry mentry;

View File

@ -619,7 +619,7 @@ enum avs_channel_config {
AVS_CHANNEL_CONFIG_DUAL_MONO = 9,
AVS_CHANNEL_CONFIG_I2S_DUAL_STEREO_0 = 10,
AVS_CHANNEL_CONFIG_I2S_DUAL_STEREO_1 = 11,
AVS_CHANNEL_CONFIG_4_CHANNEL = 12,
AVS_CHANNEL_CONFIG_7_1 = 12,
AVS_CHANNEL_CONFIG_INVALID
};

View File

@ -37,7 +37,7 @@ struct avs_path_pipeline {
struct avs_path_module {
u16 module_id;
u16 instance_id;
u8 instance_id;
union avs_gtw_attributes gtw_attrs;
struct avs_tplg_module *template;

View File

@ -468,21 +468,34 @@ static int avs_dai_fe_startup(struct snd_pcm_substream *substream, struct snd_so
host_stream = snd_hdac_ext_stream_assign(bus, substream, HDAC_EXT_STREAM_TYPE_HOST);
if (!host_stream) {
kfree(data);
return -EBUSY;
ret = -EBUSY;
goto err;
}
data->host_stream = host_stream;
snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
if (ret < 0)
goto err;
/* avoid wrap-around with wall-clock */
snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_TIME, 20, 178000000);
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_rates);
ret = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_TIME, 20, 178000000);
if (ret < 0)
goto err;
ret = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_rates);
if (ret < 0)
goto err;
snd_pcm_set_sync(substream);
dev_dbg(dai->dev, "%s fe STARTUP tag %d str %p",
__func__, hdac_stream(host_stream)->stream_tag, substream);
return 0;
err:
kfree(data);
return ret;
}
static void avs_dai_fe_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)

View File

@ -18,7 +18,7 @@ static int avs_dsp_init_probe(struct avs_dev *adev, union avs_connector_node_id
{
struct avs_probe_cfg cfg = {{0}};
struct avs_module_entry mentry;
u16 dummy;
u8 dummy;
avs_get_module_entry(adev, &AVS_PROBE_MOD_UUID, &mentry);

View File

@ -2405,6 +2405,9 @@ int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream)
if (!snd_soc_dpcm_be_can_update(fe, be, stream))
continue;
if (!snd_soc_dpcm_can_be_prepared(fe, be, stream))
continue;
if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
(be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
(be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND) &&
@ -3042,3 +3045,20 @@ int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe,
return snd_soc_dpcm_check_state(fe, be, stream, state, ARRAY_SIZE(state));
}
EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_params);
/*
* We can only prepare a BE DAI if any of it's FE are not prepared,
* running or paused for the specified stream direction.
*/
int snd_soc_dpcm_can_be_prepared(struct snd_soc_pcm_runtime *fe,
struct snd_soc_pcm_runtime *be, int stream)
{
const enum snd_soc_dpcm_state state[] = {
SND_SOC_DPCM_STATE_START,
SND_SOC_DPCM_STATE_PAUSED,
SND_SOC_DPCM_STATE_PREPARE,
};
return snd_soc_dpcm_check_state(fe, be, stream, state, ARRAY_SIZE(state));
}
EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_prepared);