};
} __packed;
+struct sof_dai_private_data {
+ struct sof_ipc_comp_dai *comp_dai;
+ struct sof_ipc_dai_config *dai_config;
+};
+
#endif
int channel)
{
struct snd_sof_widget *swidget = w->dobj.private;
+ struct sof_dai_private_data *private;
struct sof_ipc_dai_config *config;
struct snd_sof_dai *sof_dai;
sof_dai = swidget->private;
- if (!sof_dai || !sof_dai->dai_config) {
- dev_err(swidget->scomp->dev, "error: No config for DAI %s\n", w->name);
+ if (!sof_dai || !sof_dai->private) {
+ dev_err(swidget->scomp->dev, "%s: No private data for DAI %s\n", __func__,
+ w->name);
return NULL;
}
- config = &sof_dai->dai_config[sof_dai->current_config];
+ private = sof_dai->private;
+ if (!private->dai_config) {
+ dev_err(swidget->scomp->dev, "%s: No config for DAI %s\n", __func__, w->name);
+ return NULL;
+ }
+
+ config = &private->dai_config[sof_dai->current_config];
/* update config with stream tag */
config->hda.link_dma_ch = channel;
struct snd_sof_widget *swidget = w->dobj.private;
struct snd_soc_component *component = swidget->scomp;
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
+ struct sof_dai_private_data *private;
struct sof_ipc_dai_config *config;
struct snd_sof_dai *sof_dai;
struct sof_ipc_reply reply;
sof_dai = swidget->private;
- if (!sof_dai || !sof_dai->dai_config) {
- dev_err(sdev->dev, "No config for DAI %s\n", w->name);
+ if (!sof_dai || !sof_dai->private) {
+ dev_err(sdev->dev, "%s: No private data for DAI %s\n", __func__, w->name);
+ return -EINVAL;
+ }
+
+ private = sof_dai->private;
+ if (!private->dai_config) {
+ dev_err(sdev->dev, "%s: No config for DAI %s\n", __func__, w->name);
return -EINVAL;
}
- config = &sof_dai->dai_config[sof_dai->current_config];
+ config = &private->dai_config[sof_dai->current_config];
/* set PAUSE command flag */
config->flags = FIELD_PREP(SOF_DAI_CONFIG_FLAGS_CMD_MASK, SOF_DAI_CONFIG_FLAGS_PAUSE);
struct snd_soc_component *component = swidget->scomp;
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
struct sof_ipc_dai_config *config;
+ struct sof_dai_private_data *private;
struct snd_sof_dai *sof_dai;
struct sof_ipc_reply reply;
int ret;
sof_dai = swidget->private;
- if (!sof_dai || !sof_dai->dai_config) {
- dev_err(sdev->dev, "No config for DAI %s\n", w->name);
+ if (!sof_dai || !sof_dai->private) {
+ dev_err(sdev->dev, "%s: No private data for DAI %s\n", __func__, w->name);
+ return -EINVAL;
+ }
+
+ private = sof_dai->private;
+ if (!private->dai_config) {
+ dev_err(sdev->dev, "%s: No config for DAI %s\n", __func__, w->name);
return -EINVAL;
}
return ret;
}
- config = &sof_dai->dai_config[sof_dai->current_config];
+ config = &private->dai_config[sof_dai->current_config];
/*
* For static pipelines, the DAI widget would already be set up and calling
struct snd_sof_widget *swidget = w->dobj.private;
struct snd_soc_component *component = swidget->scomp;
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
+ struct sof_dai_private_data *private;
struct sof_ipc_dai_config *config;
struct snd_sof_dai *sof_dai;
struct sof_ipc_reply reply;
sof_dai = swidget->private;
- if (!sof_dai || !sof_dai->dai_config) {
- dev_err(sdev->dev, "error: No config to free DAI %s\n", w->name);
+ if (!sof_dai || !sof_dai->private) {
+ dev_err(sdev->dev, "%s: No private data for DAI %s\n", __func__, w->name);
+ return -EINVAL;
+ }
+
+ private = sof_dai->private;
+ if (!private->dai_config) {
+ dev_err(sdev->dev, "%s: No config for DAI %s\n", __func__, w->name);
return -EINVAL;
}
if (!sof_dai->configured)
return 0;
- config = &sof_dai->dai_config[sof_dai->current_config];
+ config = &private->dai_config[sof_dai->current_config];
/* set HW_FREE flag along with any quirks */
config->flags = SOF_DAI_CONFIG_FLAGS_HW_FREE |
int link_id, int alh_stream_id, int dai_id, bool setup)
{
struct snd_sof_widget *swidget = w->dobj.private;
+ struct sof_dai_private_data *private;
struct sof_ipc_dai_config *config;
struct snd_sof_dai *sof_dai;
sof_dai = swidget->private;
- if (!sof_dai || !sof_dai->dai_config) {
- dev_err(sdev->dev, "error: No config for DAI %s\n", w->name);
+ if (!sof_dai || !sof_dai->private) {
+ dev_err(sdev->dev, "%s: No private data for DAI %s\n", __func__, w->name);
+ return -EINVAL;
+ }
+
+ private = sof_dai->private;
+ if (!private->dai_config) {
+ dev_err(sdev->dev, "%s: No config for DAI %s\n", __func__, w->name);
return -EINVAL;
}
- config = &sof_dai->dai_config[sof_dai->current_config];
+ config = &private->dai_config[sof_dai->current_config];
/* update config with link and stream ID */
config->dai_index = (link_id << 8) | dai_id;
if (!dai->name || strcmp(link_name, dai->name))
continue;
for (i = 0; i < dai->number_configs; i++) {
- config = &dai->dai_config[i];
+ struct sof_dai_private_data *private = dai->private;
+
+ config = &private->dai_config[i];
if (config->ssp.fsync_rate == params_rate(params)) {
dev_dbg(sdev->dev, "DAI config %d matches pcm hw params\n", i);
dai->current_config = i;
struct snd_sof_dai *dai =
snd_sof_find_dai(component, (char *)rtd->dai_link->name);
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
+ struct sof_dai_private_data *private = dai->private;
struct snd_soc_dpcm *dpcm;
/* no topology exists for this BE, try a common configuration */
/* read format from topology */
snd_mask_none(fmt);
- switch (dai->comp_dai->config.frame_fmt) {
+ switch (private->comp_dai->config.frame_fmt) {
case SOF_IPC_FRAME_S16_LE:
snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
break;
}
/* read rate and channels from topology */
- switch (dai->dai_config->type) {
+ switch (private->dai_config->type) {
case SOF_DAI_INTEL_SSP:
/* search for config to pcm params match, if not found use default */
ssp_dai_config_pcm_params_match(sdev, (char *)rtd->dai_link->name, params);
- rate->min = dai->dai_config[dai->current_config].ssp.fsync_rate;
- rate->max = dai->dai_config[dai->current_config].ssp.fsync_rate;
- channels->min = dai->dai_config[dai->current_config].ssp.tdm_slots;
- channels->max = dai->dai_config[dai->current_config].ssp.tdm_slots;
+ rate->min = private->dai_config[dai->current_config].ssp.fsync_rate;
+ rate->max = private->dai_config[dai->current_config].ssp.fsync_rate;
+ channels->min = private->dai_config[dai->current_config].ssp.tdm_slots;
+ channels->max = private->dai_config[dai->current_config].ssp.tdm_slots;
dev_dbg(component->dev,
"rate_min: %d rate_max: %d\n", rate->min, rate->max);
break;
case SOF_DAI_INTEL_DMIC:
/* DMIC only supports 16 or 32 bit formats */
- if (dai->comp_dai->config.frame_fmt == SOF_IPC_FRAME_S24_4LE) {
+ if (private->comp_dai->config.frame_fmt == SOF_IPC_FRAME_S24_4LE) {
dev_err(component->dev,
"error: invalid fmt %d for DAI type %d\n",
- dai->comp_dai->config.frame_fmt,
- dai->dai_config->type);
+ private->comp_dai->config.frame_fmt,
+ private->dai_config->type);
}
break;
case SOF_DAI_INTEL_HDA:
* Dai could run with different channel count compared with
* front end, so get dai channel count from topology
*/
- channels->min = dai->dai_config->alh.channels;
- channels->max = dai->dai_config->alh.channels;
+ channels->min = private->dai_config->alh.channels;
+ channels->max = private->dai_config->alh.channels;
break;
case SOF_DAI_IMX_ESAI:
- rate->min = dai->dai_config->esai.fsync_rate;
- rate->max = dai->dai_config->esai.fsync_rate;
- channels->min = dai->dai_config->esai.tdm_slots;
- channels->max = dai->dai_config->esai.tdm_slots;
+ rate->min = private->dai_config->esai.fsync_rate;
+ rate->max = private->dai_config->esai.fsync_rate;
+ channels->min = private->dai_config->esai.tdm_slots;
+ channels->max = private->dai_config->esai.tdm_slots;
dev_dbg(component->dev,
"rate_min: %d rate_max: %d\n", rate->min, rate->max);
channels->min, channels->max);
break;
case SOF_DAI_MEDIATEK_AFE:
- rate->min = dai->dai_config->afe.rate;
- rate->max = dai->dai_config->afe.rate;
- channels->min = dai->dai_config->afe.channels;
- channels->max = dai->dai_config->afe.channels;
+ rate->min = private->dai_config->afe.rate;
+ rate->max = private->dai_config->afe.rate;
+ channels->min = private->dai_config->afe.channels;
+ channels->max = private->dai_config->afe.channels;
dev_dbg(component->dev,
"rate_min: %d rate_max: %d\n", rate->min, rate->max);
channels->min, channels->max);
break;
case SOF_DAI_IMX_SAI:
- rate->min = dai->dai_config->sai.fsync_rate;
- rate->max = dai->dai_config->sai.fsync_rate;
- channels->min = dai->dai_config->sai.tdm_slots;
- channels->max = dai->dai_config->sai.tdm_slots;
+ rate->min = private->dai_config->sai.fsync_rate;
+ rate->max = private->dai_config->sai.fsync_rate;
+ channels->min = private->dai_config->sai.tdm_slots;
+ channels->max = private->dai_config->sai.tdm_slots;
dev_dbg(component->dev,
"rate_min: %d rate_max: %d\n", rate->min, rate->max);
channels->min, channels->max);
break;
case SOF_DAI_AMD_BT:
- rate->min = dai->dai_config->acpbt.fsync_rate;
- rate->max = dai->dai_config->acpbt.fsync_rate;
- channels->min = dai->dai_config->acpbt.tdm_slots;
- channels->max = dai->dai_config->acpbt.tdm_slots;
+ rate->min = private->dai_config->acpbt.fsync_rate;
+ rate->max = private->dai_config->acpbt.fsync_rate;
+ channels->min = private->dai_config->acpbt.tdm_slots;
+ channels->max = private->dai_config->acpbt.tdm_slots;
dev_dbg(component->dev,
"AMD_BT rate_min: %d rate_max: %d\n", rate->min, rate->max);
channels->min, channels->max);
break;
case SOF_DAI_AMD_SP:
- rate->min = dai->dai_config->acpsp.fsync_rate;
- rate->max = dai->dai_config->acpsp.fsync_rate;
- channels->min = dai->dai_config->acpsp.tdm_slots;
- channels->max = dai->dai_config->acpsp.tdm_slots;
+ rate->min = private->dai_config->acpsp.fsync_rate;
+ rate->max = private->dai_config->acpsp.fsync_rate;
+ channels->min = private->dai_config->acpsp.tdm_slots;
+ channels->max = private->dai_config->acpsp.tdm_slots;
dev_dbg(component->dev,
"AMD_SP rate_min: %d rate_max: %d\n", rate->min, rate->max);
channels->min, channels->max);
break;
case SOF_DAI_AMD_DMIC:
- rate->min = dai->dai_config->acpdmic.fsync_rate;
- rate->max = dai->dai_config->acpdmic.fsync_rate;
- channels->min = dai->dai_config->acpdmic.tdm_slots;
- channels->max = dai->dai_config->acpdmic.tdm_slots;
+ rate->min = private->dai_config->acpdmic.fsync_rate;
+ rate->max = private->dai_config->acpdmic.fsync_rate;
+ channels->min = private->dai_config->acpdmic.tdm_slots;
+ channels->max = private->dai_config->acpdmic.tdm_slots;
dev_dbg(component->dev,
"AMD_DMIC rate_min: %d rate_max: %d\n", rate->min, rate->max);
break;
default:
dev_err(component->dev, "error: invalid DAI type %d\n",
- dai->dai_config->type);
+ private->dai_config->type);
break;
}
static int sof_dai_config_setup(struct snd_sof_dev *sdev, struct snd_sof_dai *dai)
{
+ struct sof_dai_private_data *private = dai->private;
struct sof_ipc_dai_config *config;
struct sof_ipc_reply reply;
int ret;
- config = &dai->dai_config[dai->current_config];
+ config = &private->dai_config[dai->current_config];
if (!config) {
dev_err(sdev->dev, "error: no config for DAI %s\n", dai->name);
return -EINVAL;
switch (swidget->id) {
case snd_soc_dapm_dai_in:
case snd_soc_dapm_dai_out:
+ {
+ struct sof_dai_private_data *dai_data;
+
dai = swidget->private;
- comp = &dai->comp_dai->comp;
+ dai_data = dai->private;
+ comp = &dai_data->comp_dai->comp;
dai->configured = false;
- ret = sof_ipc_tx_message(sdev->ipc, comp->hdr.cmd, dai->comp_dai, comp->hdr.size,
- &r, sizeof(r));
+ ret = sof_ipc_tx_message(sdev->ipc, comp->hdr.cmd, dai_data->comp_dai,
+ comp->hdr.size, &r, sizeof(r));
if (ret < 0) {
dev_err(sdev->dev, "error: failed to load widget %s\n",
swidget->widget->name);
return ret;
}
break;
+ }
case snd_soc_dapm_scheduler:
pipeline = swidget->private;
ret = sof_ipc_tx_message(sdev->ipc, pipeline->hdr.cmd, pipeline,
/* update DAI config. The IPC will be sent in sof_widget_setup() */
if (WIDGET_IS_DAI(swidget->id)) {
struct snd_sof_dai *dai = swidget->private;
+ struct sof_dai_private_data *private = dai->private;
struct sof_ipc_dai_config *config;
- if (!dai || !dai->dai_config)
+ if (!dai || !private || !private->dai_config)
continue;
- config = dai->dai_config;
+ config = private->dai_config;
/*
* The link DMA channel would be invalidated for running
* streams but not for streams that were in the PAUSED
snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME);
struct snd_sof_dai *dai =
snd_sof_find_dai(component, (char *)rtd->dai_link->name);
+ struct sof_dai_private_data *private = dai->private;
/* use the tplg configured mclk if existed */
- if (!dai || !dai->dai_config)
+ if (!dai || !private || !private->dai_config)
return 0;
- switch (dai->dai_config->type) {
+ switch (private->dai_config->type) {
case SOF_DAI_INTEL_SSP:
switch (clk_type) {
case SOF_DAI_CLK_INTEL_SSP_MCLK:
- return dai->dai_config->ssp.mclk_rate;
+ return private->dai_config->ssp.mclk_rate;
case SOF_DAI_CLK_INTEL_SSP_BCLK:
- return dai->dai_config->ssp.bclk_rate;
+ return private->dai_config->ssp.bclk_rate;
default:
dev_err(rtd->dev, "fail to get SSP clk %d rate\n",
clk_type);
default:
/* not yet implemented for platforms other than the above */
dev_err(rtd->dev, "DAI type %d not supported yet!\n",
- dai->dai_config->type);
+ private->dai_config->type);
return -EINVAL;
}
}
struct snd_soc_component *scomp;
const char *name;
- struct sof_ipc_comp_dai *comp_dai;
int number_configs;
int current_config;
bool configured; /* DAI configured during BE hw_params */
- struct sof_ipc_dai_config *dai_config;
struct list_head list; /* list in sdev dai list */
+ void *private;
};
/*
struct snd_sof_dai *dai)
{
struct snd_soc_tplg_private *private = &tw->priv;
+ struct sof_dai_private_data *dai_data;
struct sof_ipc_comp_dai *comp_dai;
size_t ipc_size = sizeof(*comp_dai);
int ret;
+ dai_data = kzalloc(sizeof(*dai_data), GFP_KERNEL);
+ if (!dai_data)
+ return -ENOMEM;
+
comp_dai = (struct sof_ipc_comp_dai *)
sof_comp_alloc(swidget, &ipc_size, index);
- if (!comp_dai)
- return -ENOMEM;
+ if (!comp_dai) {
+ ret = -ENOMEM;
+ goto free;
+ }
/* configure dai IPC message */
comp_dai->comp.type = SOF_COMP_DAI;
if (ret != 0) {
dev_err(scomp->dev, "error: parse dai tokens failed %d\n",
le32_to_cpu(private->size));
- return ret;
+ goto free;
}
ret = sof_parse_tokens(scomp, &comp_dai->config, comp_tokens,
if (ret != 0) {
dev_err(scomp->dev, "error: parse dai.cfg tokens failed %d\n",
private->size);
- return ret;
+ goto free;
}
dev_dbg(scomp->dev, "dai %s: type %d index %d\n",
if (dai) {
dai->scomp = scomp;
- dai->comp_dai = comp_dai;
+ dai_data->comp_dai = comp_dai;
+ dai->private = dai_data;
}
+ return 0;
+
+free:
+ kfree(dai_data);
return ret;
}
dai = swidget->private;
if (dai) {
- kfree(dai->comp_dai);
- /* free dai config */
- kfree(dai->dai_config);
+ struct sof_dai_private_data *dai_data = dai->private;
+
+ kfree(dai_data->comp_dai);
+ kfree(dai_data->dai_config);
+ kfree(dai_data);
list_del(&dai->list);
}
break;
struct sof_ipc_dai_config *config,
int num_conf, int curr_conf)
{
+ struct sof_dai_private_data *dai_data;
struct snd_sof_dai *dai;
int found = 0;
int i;
list_for_each_entry(dai, &sdev->dai_list, list) {
+ dai_data = dai->private;
if (!dai->name)
continue;
* dai_index.
*/
for (i = 0; i < num_conf; i++)
- config[i].dai_index = dai->comp_dai->dai_index;
+ config[i].dai_index = dai_data->comp_dai->dai_index;
dev_dbg(sdev->dev, "set DAI config for %s index %d\n",
dai->name, config[curr_conf].dai_index);
dai->number_configs = num_conf;
dai->current_config = curr_conf;
- dai->dai_config = kmemdup(config, size * num_conf, GFP_KERNEL);
- if (!dai->dai_config)
+ dai_data->dai_config = kmemdup(config, size * num_conf, GFP_KERNEL);
+ if (!dai_data->dai_config)
return -ENOMEM;
found = 1;