Skip to content

Commit 2ff1981

Browse files
povikjannau
authored andcommitted
ASoC: apple: mca: Support FEs being clock consumers
Support FEs being I2S clock consumers. This does not mean we support accepting clocks from outside the SoC (although it paves the way for that support in the future), but it means multiple FEs can attach to one BE, one being clock producer and the rest clock consumers. This is useful for grabbing I/V sense data on some machines, since in such a scenario the format of the sense data on the I2S bus differs from that of the audio data (the two formats differing in slot width). With two FEs attached to the bus, we can split the responsibilities and command different slot widths to the two. Signed-off-by: Martin Povišer <povik+lin@cutebit.org>
1 parent ecc7478 commit 2ff1981

1 file changed

Lines changed: 88 additions & 21 deletions

File tree

sound/soc/apple/mca.c

Lines changed: 88 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,8 @@ struct mca_cluster {
133133
struct clk *clk_parent;
134134
struct dma_chan *dma_chans[SNDRV_PCM_STREAM_LAST + 1];
135135

136+
bool clk_provider;
137+
136138
bool port_clk_started[SNDRV_PCM_STREAM_LAST + 1];
137139
int port_clk_driver; /* The cluster driving this cluster's port */
138140

@@ -256,11 +258,32 @@ static int mca_fe_trigger(struct snd_pcm_substream *substream, int cmd,
256258
return 0;
257259
}
258260

261+
static int mca_fe_get_port(struct snd_pcm_substream *substream)
262+
{
263+
struct snd_soc_pcm_runtime *fe = snd_soc_substream_to_rtd(substream);
264+
struct snd_soc_pcm_runtime *be;
265+
struct snd_soc_dpcm *dpcm;
266+
267+
be = NULL;
268+
for_each_dpcm_be(fe, substream->stream, dpcm) {
269+
be = dpcm->be;
270+
break;
271+
}
272+
273+
if (!be)
274+
return -EINVAL;
275+
276+
return mca_dai_to_cluster(snd_soc_rtd_to_cpu(be, 0))->no;
277+
}
278+
259279
static int mca_fe_enable_clocks(struct mca_cluster *cl)
260280
{
261281
struct mca_data *mca = cl->host;
262282
int ret;
263283

284+
if (!cl->clk_provider)
285+
return -EINVAL;
286+
264287
ret = clk_prepare_enable(cl->clk_parent);
265288
if (ret) {
266289
dev_err(mca->dev,
@@ -334,7 +357,7 @@ static int mca_be_prepare(struct snd_pcm_substream *substream,
334357
int ret;
335358

336359
if (cl->port_clk_driver < 0)
337-
return -EINVAL;
360+
return 0;
338361

339362
fe_cl = &mca->clusters[cl->port_clk_driver];
340363

@@ -355,6 +378,44 @@ static int mca_be_prepare(struct snd_pcm_substream *substream,
355378
return 0;
356379
}
357380

381+
static int mca_fe_prepare(struct snd_pcm_substream *substream,
382+
struct snd_soc_dai *dai)
383+
{
384+
struct mca_cluster *cl = mca_dai_to_cluster(dai);
385+
struct mca_data *mca = cl->host;
386+
387+
if (cl->clk_provider)
388+
return 0;
389+
390+
if (!mca_fe_clocks_in_use(cl)) {
391+
int port = mca_fe_get_port(substream);
392+
writel_relaxed(port + 6 + 1,
393+
cl->base + REG_SYNCGEN_MCLK_SEL);
394+
mca_modify(cl, REG_SYNCGEN_STATUS, SYNCGEN_STATUS_EN,
395+
SYNCGEN_STATUS_EN);
396+
}
397+
cl->clocks_in_use[substream->stream] = true;
398+
399+
return 0;
400+
}
401+
402+
static int mca_fe_hw_free(struct snd_pcm_substream *substream,
403+
struct snd_soc_dai *dai)
404+
{
405+
struct mca_cluster *cl = mca_dai_to_cluster(dai);
406+
407+
if (cl->clk_provider)
408+
return 0;
409+
410+
cl->clocks_in_use[substream->stream] = false;
411+
if (mca_fe_clocks_in_use(cl))
412+
return 0;
413+
414+
mca_modify(cl, REG_SYNCGEN_STATUS, SYNCGEN_STATUS_EN, 0);
415+
416+
return 0;
417+
}
418+
358419
static unsigned int mca_crop_mask(unsigned int mask, int nchans)
359420
{
360421
while (hweight32(mask) > nchans)
@@ -480,9 +541,18 @@ static int mca_fe_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
480541
u32 serdes_conf = 0;
481542
u32 bitstart;
482543

483-
if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) !=
484-
SND_SOC_DAIFMT_BP_FP)
544+
switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
545+
case SND_SOC_DAIFMT_BP_FP:
546+
cl->clk_provider = true;
547+
break;
548+
549+
case SND_SOC_DAIFMT_BC_FC:
550+
cl->clk_provider = false;
551+
break;
552+
553+
default:
485554
goto err;
555+
}
486556

487557
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
488558
case SND_SOC_DAIFMT_I2S:
@@ -539,24 +609,6 @@ static int mca_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
539609
return 0;
540610
}
541611

542-
static int mca_fe_get_port(struct snd_pcm_substream *substream)
543-
{
544-
struct snd_soc_pcm_runtime *fe = snd_soc_substream_to_rtd(substream);
545-
struct snd_soc_pcm_runtime *be;
546-
struct snd_soc_dpcm *dpcm;
547-
548-
be = NULL;
549-
for_each_dpcm_be(fe, substream->stream, dpcm) {
550-
be = dpcm->be;
551-
break;
552-
}
553-
554-
if (!be)
555-
return -EINVAL;
556-
557-
return mca_dai_to_cluster(snd_soc_rtd_to_cpu(be, 0))->no;
558-
}
559-
560612
static int mca_fe_hw_params(struct snd_pcm_substream *substream,
561613
struct snd_pcm_hw_params *params,
562614
struct snd_soc_dai *dai)
@@ -681,6 +733,8 @@ static const struct snd_soc_dai_ops mca_fe_ops = {
681733
.set_tdm_slot = mca_fe_set_tdm_slot,
682734
.hw_params = mca_fe_hw_params,
683735
.trigger = mca_fe_trigger,
736+
.prepare = mca_fe_prepare,
737+
.hw_free = mca_fe_hw_free,
684738
};
685739

686740
/*
@@ -734,6 +788,9 @@ static int mca_be_startup(struct snd_pcm_substream *substream,
734788
PORT_ENABLES_TX_DATA);
735789
}
736790

791+
if (!fe_cl->clk_provider)
792+
return 0;
793+
737794
if (mca_be_clk_started(cl)) {
738795
/*
739796
* Port is already started in the other direction.
@@ -763,7 +820,10 @@ static int mca_be_startup(struct snd_pcm_substream *substream,
763820
static void mca_be_shutdown(struct snd_pcm_substream *substream,
764821
struct snd_soc_dai *dai)
765822
{
823+
struct snd_soc_pcm_runtime *be = snd_soc_substream_to_rtd(substream);
824+
struct snd_soc_pcm_runtime *fe = mca_be_get_fe(be, substream->stream);
766825
struct mca_cluster *cl = mca_dai_to_cluster(dai);
826+
struct mca_cluster *fe_cl;
767827
struct mca_data *mca = cl->host;
768828

769829
if (cl->clocks_in_use[substream->stream] &&
@@ -786,11 +846,18 @@ static void mca_be_shutdown(struct snd_pcm_substream *substream,
786846
mca_fe_disable_clocks(fe_cl);
787847
}
788848

849+
if (!fe)
850+
return;
851+
fe_cl = mca_dai_to_cluster(snd_soc_rtd_to_cpu(fe, 0));
852+
789853
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
790854
mca_modify(cl, REG_PORT_ENABLES, PORT_ENABLES_TX_DATA, 0);
791855
writel_relaxed(0, cl->base + REG_PORT_DATA_SEL);
792856
}
793857

858+
if (!fe_cl->clk_provider)
859+
return;
860+
794861
cl->port_clk_started[substream->stream] = false;
795862
if (!mca_be_clk_started(cl)) {
796863
/*

0 commit comments

Comments
 (0)