Skip to content

Commit b9062f9

Browse files
crojewsk-intelbroonie
authored andcommitted
ASoC: Intel: avs: non-HDA PCM BE operations
DMIC and I2S interfaces differ in DMA operations from the HDAudio interface. With that in mind, implement all DAI operations to handle non-HDA BE interfaces. To prevent code duplication in newly added code, I2S platform registering is dynamic - makes use of specified port_mask and TDMs array to populate as many DAIs as required. Signed-off-by: Amadeusz Sławiński <[email protected]> Signed-off-by: Cezary Rojewski <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Mark Brown <[email protected]>
1 parent 9114700 commit b9062f9

File tree

2 files changed

+225
-1
lines changed

2 files changed

+225
-1
lines changed

sound/soc/intel/avs/avs.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,4 +270,8 @@ struct avs_soc_component {
270270

271271
extern const struct snd_soc_dai_ops avs_dai_fe_ops;
272272

273+
int avs_dmic_platform_register(struct avs_dev *adev, const char *name);
274+
int avs_i2s_platform_register(struct avs_dev *adev, const char *name, unsigned long port_mask,
275+
unsigned long *tdms);
276+
273277
#endif /* __SOUND_SOC_INTEL_AVS_H */

sound/soc/intel/avs/pcm.c

Lines changed: 221 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,23 @@ static int avs_dai_hw_params(struct snd_pcm_substream *substream,
112112
return 0;
113113
}
114114

115+
static int avs_dai_be_hw_params(struct snd_pcm_substream *substream,
116+
struct snd_pcm_hw_params *be_hw_params, struct snd_soc_dai *dai,
117+
int dma_id)
118+
{
119+
struct snd_pcm_hw_params *fe_hw_params = NULL;
120+
struct snd_soc_pcm_runtime *fe, *be;
121+
struct snd_soc_dpcm *dpcm;
122+
123+
be = asoc_substream_to_rtd(substream);
124+
for_each_dpcm_fe(be, substream->stream, dpcm) {
125+
fe = dpcm->fe;
126+
fe_hw_params = &fe->dpcm[substream->stream].hw_params;
127+
}
128+
129+
return avs_dai_hw_params(substream, fe_hw_params, be_hw_params, dai, dma_id);
130+
}
131+
115132
static int avs_dai_prepare(struct avs_dev *adev, struct snd_pcm_substream *substream,
116133
struct snd_soc_dai *dai)
117134
{
@@ -134,6 +151,100 @@ static int avs_dai_prepare(struct avs_dev *adev, struct snd_pcm_substream *subst
134151
return ret;
135152
}
136153

154+
static int avs_dai_nonhda_be_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
155+
{
156+
return avs_dai_startup(substream, dai, false);
157+
}
158+
159+
static void avs_dai_nonhda_be_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
160+
{
161+
struct avs_dma_data *data;
162+
163+
data = snd_soc_dai_get_dma_data(dai, substream);
164+
165+
snd_soc_dai_set_dma_data(dai, substream, NULL);
166+
kfree(data);
167+
}
168+
169+
static int avs_dai_nonhda_be_hw_params(struct snd_pcm_substream *substream,
170+
struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *dai)
171+
{
172+
struct avs_dma_data *data;
173+
174+
data = snd_soc_dai_get_dma_data(dai, substream);
175+
if (data->path)
176+
return 0;
177+
178+
/* Actual port-id comes from topology. */
179+
return avs_dai_be_hw_params(substream, hw_params, dai, 0);
180+
}
181+
182+
static int avs_dai_nonhda_be_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
183+
{
184+
struct avs_dma_data *data;
185+
186+
dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
187+
188+
data = snd_soc_dai_get_dma_data(dai, substream);
189+
if (data->path) {
190+
avs_path_free(data->path);
191+
data->path = NULL;
192+
}
193+
194+
return 0;
195+
}
196+
197+
static int avs_dai_nonhda_be_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
198+
{
199+
return avs_dai_prepare(to_avs_dev(dai->dev), substream, dai);
200+
}
201+
202+
static int avs_dai_nonhda_be_trigger(struct snd_pcm_substream *substream, int cmd,
203+
struct snd_soc_dai *dai)
204+
{
205+
struct avs_dma_data *data;
206+
int ret = 0;
207+
208+
data = snd_soc_dai_get_dma_data(dai, substream);
209+
210+
switch (cmd) {
211+
case SNDRV_PCM_TRIGGER_START:
212+
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
213+
ret = avs_path_run(data->path, AVS_TPLG_TRIGGER_AUTO);
214+
if (ret < 0)
215+
dev_err(dai->dev, "run BE path failed: %d\n", ret);
216+
break;
217+
218+
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
219+
case SNDRV_PCM_TRIGGER_STOP:
220+
ret = avs_path_pause(data->path);
221+
if (ret < 0)
222+
dev_err(dai->dev, "pause BE path failed: %d\n", ret);
223+
224+
if (cmd == SNDRV_PCM_TRIGGER_STOP) {
225+
ret = avs_path_reset(data->path);
226+
if (ret < 0)
227+
dev_err(dai->dev, "reset BE path failed: %d\n", ret);
228+
}
229+
break;
230+
231+
default:
232+
ret = -EINVAL;
233+
break;
234+
}
235+
236+
return ret;
237+
}
238+
239+
static const struct snd_soc_dai_ops avs_dai_nonhda_be_ops = {
240+
.startup = avs_dai_nonhda_be_startup,
241+
.shutdown = avs_dai_nonhda_be_shutdown,
242+
.hw_params = avs_dai_nonhda_be_hw_params,
243+
.hw_free = avs_dai_nonhda_be_hw_free,
244+
.prepare = avs_dai_nonhda_be_prepare,
245+
.trigger = avs_dai_nonhda_be_trigger,
246+
};
247+
137248
static const unsigned int rates[] = {
138249
8000, 11025, 12000, 16000,
139250
22050, 24000, 32000, 44100,
@@ -589,7 +700,6 @@ static const struct snd_soc_component_driver avs_component_driver = {
589700
.non_legacy_dai_naming = true,
590701
};
591702

592-
__maybe_unused
593703
static int avs_soc_component_register(struct device *dev, const char *name,
594704
const struct snd_soc_component_driver *drv,
595705
struct snd_soc_dai_driver *cpu_dais, int num_cpu_dais)
@@ -611,3 +721,113 @@ static int avs_soc_component_register(struct device *dev, const char *name,
611721

612722
return snd_soc_add_component(&acomp->base, cpu_dais, num_cpu_dais);
613723
}
724+
725+
static struct snd_soc_dai_driver dmic_cpu_dais[] = {
726+
{
727+
.name = "DMIC Pin",
728+
.ops = &avs_dai_nonhda_be_ops,
729+
.capture = {
730+
.stream_name = "DMIC Rx",
731+
.channels_min = 1,
732+
.channels_max = 4,
733+
.rates = SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_48000,
734+
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
735+
},
736+
},
737+
{
738+
.name = "DMIC WoV Pin",
739+
.ops = &avs_dai_nonhda_be_ops,
740+
.capture = {
741+
.stream_name = "DMIC WoV Rx",
742+
.channels_min = 1,
743+
.channels_max = 4,
744+
.rates = SNDRV_PCM_RATE_16000,
745+
.formats = SNDRV_PCM_FMTBIT_S16_LE,
746+
},
747+
},
748+
};
749+
750+
int avs_dmic_platform_register(struct avs_dev *adev, const char *name)
751+
{
752+
return avs_soc_component_register(adev->dev, name, &avs_component_driver, dmic_cpu_dais,
753+
ARRAY_SIZE(dmic_cpu_dais));
754+
}
755+
756+
static const struct snd_soc_dai_driver i2s_dai_template = {
757+
.ops = &avs_dai_nonhda_be_ops,
758+
.playback = {
759+
.channels_min = 1,
760+
.channels_max = 8,
761+
.rates = SNDRV_PCM_RATE_8000_192000 |
762+
SNDRV_PCM_RATE_KNOT,
763+
.formats = SNDRV_PCM_FMTBIT_S16_LE |
764+
SNDRV_PCM_FMTBIT_S24_LE |
765+
SNDRV_PCM_FMTBIT_S32_LE,
766+
},
767+
.capture = {
768+
.channels_min = 1,
769+
.channels_max = 8,
770+
.rates = SNDRV_PCM_RATE_8000_192000 |
771+
SNDRV_PCM_RATE_KNOT,
772+
.formats = SNDRV_PCM_FMTBIT_S16_LE |
773+
SNDRV_PCM_FMTBIT_S24_LE |
774+
SNDRV_PCM_FMTBIT_S32_LE,
775+
},
776+
};
777+
778+
int avs_i2s_platform_register(struct avs_dev *adev, const char *name, unsigned long port_mask,
779+
unsigned long *tdms)
780+
{
781+
struct snd_soc_dai_driver *cpus, *dai;
782+
size_t ssp_count, cpu_count;
783+
int i, j;
784+
785+
ssp_count = adev->hw_cfg.i2s_caps.ctrl_count;
786+
cpu_count = hweight_long(port_mask);
787+
if (tdms)
788+
for_each_set_bit(i, &port_mask, ssp_count)
789+
cpu_count += hweight_long(tdms[i]);
790+
791+
cpus = devm_kzalloc(adev->dev, sizeof(*cpus) * cpu_count, GFP_KERNEL);
792+
if (!cpus)
793+
return -ENOMEM;
794+
795+
dai = cpus;
796+
for_each_set_bit(i, &port_mask, ssp_count) {
797+
memcpy(dai, &i2s_dai_template, sizeof(*dai));
798+
799+
dai->name =
800+
devm_kasprintf(adev->dev, GFP_KERNEL, "SSP%d Pin", i);
801+
dai->playback.stream_name =
802+
devm_kasprintf(adev->dev, GFP_KERNEL, "ssp%d Tx", i);
803+
dai->capture.stream_name =
804+
devm_kasprintf(adev->dev, GFP_KERNEL, "ssp%d Rx", i);
805+
806+
if (!dai->name || !dai->playback.stream_name || !dai->capture.stream_name)
807+
return -ENOMEM;
808+
dai++;
809+
}
810+
811+
if (!tdms)
812+
goto plat_register;
813+
814+
for_each_set_bit(i, &port_mask, ssp_count) {
815+
for_each_set_bit(j, &tdms[i], ssp_count) {
816+
memcpy(dai, &i2s_dai_template, sizeof(*dai));
817+
818+
dai->name =
819+
devm_kasprintf(adev->dev, GFP_KERNEL, "SSP%d:%d Pin", i, j);
820+
dai->playback.stream_name =
821+
devm_kasprintf(adev->dev, GFP_KERNEL, "ssp%d:%d Tx", i, j);
822+
dai->capture.stream_name =
823+
devm_kasprintf(adev->dev, GFP_KERNEL, "ssp%d:%d Rx", i, j);
824+
825+
if (!dai->name || !dai->playback.stream_name || !dai->capture.stream_name)
826+
return -ENOMEM;
827+
dai++;
828+
}
829+
}
830+
831+
plat_register:
832+
return avs_soc_component_register(adev->dev, name, &avs_component_driver, cpus, cpu_count);
833+
}

0 commit comments

Comments
 (0)