* [PATCH 0/9] ASoC: apple: mca: support simultaneous I2S capture on the frontend
@ 2025-05-18 10:50 James Calligeros
2025-05-18 10:50 ` [PATCH 1/9] ASoC: apple: mca: Constrain channels according to TDM mask James Calligeros
` (9 more replies)
0 siblings, 10 replies; 12+ messages in thread
From: James Calligeros @ 2025-05-18 10:50 UTC (permalink / raw)
To: Martin Povišer, Liam Girdwood, Mark Brown, Jaroslav Kysela,
Takashi Iwai
Cc: asahi, linux-sound, linux-kernel, James Calligeros, Hector Martin
Hi all,
This series introduces a number of changes to the ASoC driver
for the Apple MCA peripheral to enable support for bidirectional
I2S. This is achieved by allowing frontends to act as clock consumers
and logically ORing data input lines when multiple backends are linked
to a frontend.
This allows the Texas Instruments speaker amps used on Apple Silicon Macs
(Apple-specific revisions of TAS2764 and TAS2770) to send their IVSENSE
data back to the SoC. Since these amps do not have any sort of integrated
speaker protection logic, we must use the IVSENSE data and the Thiele/Small
Parameters of the attached speaker(s) to implement our own in software.
---
Hector Martin (3):
ASoC: apple: mca: Move clock shutdown to backend shutdown
ASoC: apple: mca: Do not mark clocks in use for non-providers
ASoC: apple: mca: Add delay after configuring clock
James Calligeros (1):
ASoC: apple: mca: use readx_poll_timeout to check for cluster reset
Martin Povišer (5):
ASoC: apple: mca: Constrain channels according to TDM mask
ASoC: apple: mca: Separate data & clock port setup
ASoC: apple: mca: Factor out mca_be_get_fe
ASoC: apple: mca: Support FEs being clock consumers
ASoC: apple: mca: Support capture on multiples BEs
sound/soc/apple/mca.c | 336 +++++++++++++++++--------
1 file changed, 234 insertions(+), 102 deletions(-)
---
base-commit: 7163ff8cf6a2ee6b6861f0c521885e83a97145f9
change-id: 20250517-mca-fixes-666094666fa0
Best regards,
--
James Calligeros <jcalligeros99@gmail.com>
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 1/9] ASoC: apple: mca: Constrain channels according to TDM mask
2025-05-18 10:50 [PATCH 0/9] ASoC: apple: mca: support simultaneous I2S capture on the frontend James Calligeros
@ 2025-05-18 10:50 ` James Calligeros
2025-05-18 10:50 ` [PATCH 2/9] ASoC: apple: mca: use readx_poll_timeout to check for cluster reset James Calligeros
` (8 subsequent siblings)
9 siblings, 0 replies; 12+ messages in thread
From: James Calligeros @ 2025-05-18 10:50 UTC (permalink / raw)
To: Martin Povišer, Liam Girdwood, Mark Brown, Jaroslav Kysela,
Takashi Iwai
Cc: asahi, linux-sound, linux-kernel, James Calligeros
From: Martin Povišer <povik+lin@cutebit.org>
We don't (and can't) configure the hardware correctly if the number of
channels exceeds the weight of the TDM mask. Report that constraint in
startup of FE.
Fixes: 3df5d0d97289 ("ASoC: apple: mca: Start new platform driver")
Signed-off-by: Martin Povišer <povik+lin@cutebit.org>
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
---
sound/soc/apple/mca.c | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/sound/soc/apple/mca.c b/sound/soc/apple/mca.c
index b4f4696809dd231a64229114c5550bb5f237607f..5dd24ab90d0f052bb48f451cf009dc2e9128014d 100644
--- a/sound/soc/apple/mca.c
+++ b/sound/soc/apple/mca.c
@@ -464,6 +464,28 @@ static int mca_configure_serdes(struct mca_cluster *cl, int serdes_unit,
return -EINVAL;
}
+static int mca_fe_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mca_cluster *cl = mca_dai_to_cluster(dai);
+ unsigned int mask, nchannels;
+
+ if (cl->tdm_slots) {
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ mask = cl->tdm_tx_mask;
+ else
+ mask = cl->tdm_rx_mask;
+
+ nchannels = hweight32(mask);
+ } else {
+ nchannels = 2;
+ }
+
+ return snd_pcm_hw_constraint_minmax(substream->runtime,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ 1, nchannels);
+}
+
static int mca_fe_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
unsigned int rx_mask, int slots, int slot_width)
{
@@ -680,6 +702,7 @@ static int mca_fe_hw_params(struct snd_pcm_substream *substream,
}
static const struct snd_soc_dai_ops mca_fe_ops = {
+ .startup = mca_fe_startup,
.set_fmt = mca_fe_set_fmt,
.set_bclk_ratio = mca_set_bclk_ratio,
.set_tdm_slot = mca_fe_set_tdm_slot,
--
2.49.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 2/9] ASoC: apple: mca: use readx_poll_timeout to check for cluster reset
2025-05-18 10:50 [PATCH 0/9] ASoC: apple: mca: support simultaneous I2S capture on the frontend James Calligeros
2025-05-18 10:50 ` [PATCH 1/9] ASoC: apple: mca: Constrain channels according to TDM mask James Calligeros
@ 2025-05-18 10:50 ` James Calligeros
2025-05-18 10:50 ` [PATCH 3/9] ASoC: apple: mca: Move clock shutdown to backend shutdown James Calligeros
` (7 subsequent siblings)
9 siblings, 0 replies; 12+ messages in thread
From: James Calligeros @ 2025-05-18 10:50 UTC (permalink / raw)
To: Martin Povišer, Liam Girdwood, Mark Brown, Jaroslav Kysela,
Takashi Iwai
Cc: asahi, linux-sound, linux-kernel, James Calligeros
MCA clusters should take no longer than 1 microsecond to reset, however
it has been observed to take longer on very rare occasions.
Rather than just add an unreasonably long usleep(), use readx_poll_timeout
to poll the status register for a clear reset bit. This lets us have a
very safe maximum wait time, but continue early if we are ready to do so.
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
---
sound/soc/apple/mca.c | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/sound/soc/apple/mca.c b/sound/soc/apple/mca.c
index 5dd24ab90d0f052bb48f451cf009dc2e9128014d..7113da4bdea7b687c0d44d2bbf3a511b8299056f 100644
--- a/sound/soc/apple/mca.c
+++ b/sound/soc/apple/mca.c
@@ -24,6 +24,7 @@
#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/init.h>
+#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -197,6 +198,7 @@ static void mca_fe_early_trigger(struct snd_pcm_substream *substream, int cmd,
int serdes_unit = is_tx ? CLUSTER_TX_OFF : CLUSTER_RX_OFF;
int serdes_conf =
serdes_unit + (is_tx ? REG_TX_SERDES_CONF : REG_RX_SERDES_CONF);
+ int ret, status;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
@@ -211,11 +213,15 @@ static void mca_fe_early_trigger(struct snd_pcm_substream *substream, int cmd,
SERDES_STATUS_RST);
/*
* Experiments suggest that it takes at most ~1 us
- * for the bit to clear, so wait 2 us for good measure.
+ * for the bit to clear, however this has been seen to fail.
+ * Wait up to 50 us for the reset bit to clear.
*/
- udelay(2);
- WARN_ON(readl_relaxed(cl->base + serdes_unit + REG_SERDES_STATUS) &
- SERDES_STATUS_RST);
+ ret = readx_poll_timeout(readl_relaxed,
+ cl->base + serdes_unit + REG_SERDES_STATUS,
+ status, !(status & SERDES_STATUS_RST), 2, 50);
+ if (ret || (status & SERDES_STATUS_RST))
+ dev_warn(cl->host->dev, "MCA cluster failed to reset\n");
+
mca_modify(cl, serdes_conf, SERDES_CONF_SYNC_SEL,
FIELD_PREP(SERDES_CONF_SYNC_SEL, 0));
mca_modify(cl, serdes_conf, SERDES_CONF_SYNC_SEL,
--
2.49.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 3/9] ASoC: apple: mca: Move clock shutdown to backend shutdown
2025-05-18 10:50 [PATCH 0/9] ASoC: apple: mca: support simultaneous I2S capture on the frontend James Calligeros
2025-05-18 10:50 ` [PATCH 1/9] ASoC: apple: mca: Constrain channels according to TDM mask James Calligeros
2025-05-18 10:50 ` [PATCH 2/9] ASoC: apple: mca: use readx_poll_timeout to check for cluster reset James Calligeros
@ 2025-05-18 10:50 ` James Calligeros
2025-05-19 10:38 ` Mark Brown
2025-05-18 10:50 ` [PATCH 4/9] ASoC: apple: mca: Separate data & clock port setup James Calligeros
` (6 subsequent siblings)
9 siblings, 1 reply; 12+ messages in thread
From: James Calligeros @ 2025-05-18 10:50 UTC (permalink / raw)
To: Martin Povišer, Liam Girdwood, Mark Brown, Jaroslav Kysela,
Takashi Iwai
Cc: asahi, linux-sound, linux-kernel, Hector Martin, James Calligeros
From: Hector Martin <marcan@marcan.st>
Codecs are set to mute after hw_free, so yanking the clock out from
under them in hw_free leads to breakage. Move the clock shutdown to the
shutdown op, which is late enough.
Signed-off-by: Hector Martin <marcan@marcan.st>
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
---
sound/soc/apple/mca.c | 48 +++++++++++--------------
1 file changed, 20 insertions(+), 28 deletions(-)
diff --git a/sound/soc/apple/mca.c b/sound/soc/apple/mca.c
index 7113da4bdea7b687c0d44d2bbf3a511b8299056f..69f2e852d4aeb2d53eea5d7fee400b2337a09065 100644
--- a/sound/soc/apple/mca.c
+++ b/sound/soc/apple/mca.c
@@ -361,33 +361,6 @@ static int mca_be_prepare(struct snd_pcm_substream *substream,
return 0;
}
-static int mca_be_hw_free(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct mca_cluster *cl = mca_dai_to_cluster(dai);
- struct mca_data *mca = cl->host;
- struct mca_cluster *fe_cl;
-
- if (cl->port_driver < 0)
- return -EINVAL;
-
- /*
- * We are operating on a foreign cluster here, but since we
- * belong to the same PCM, accesses should have been
- * synchronized at ASoC level.
- */
- fe_cl = &mca->clusters[cl->port_driver];
- if (!mca_fe_clocks_in_use(fe_cl))
- return 0; /* Nothing to do */
-
- cl->clocks_in_use[substream->stream] = false;
-
- if (!mca_fe_clocks_in_use(fe_cl))
- mca_fe_disable_clocks(fe_cl);
-
- return 0;
-}
-
static unsigned int mca_crop_mask(unsigned int mask, int nchans)
{
while (hweight32(mask) > nchans)
@@ -785,6 +758,26 @@ static void mca_be_shutdown(struct snd_pcm_substream *substream,
struct mca_cluster *cl = mca_dai_to_cluster(dai);
struct mca_data *mca = cl->host;
+ if (cl->clocks_in_use[substream->stream] &&
+ !WARN_ON(cl->port_driver < 0)) {
+ struct mca_cluster *fe_cl = &mca->clusters[cl->port_driver];
+
+ /*
+ * Typically the CODECs we are paired with will require clocks
+ * to be present at time of mute with the 'mute_stream' op.
+ * We need to disable the clocks here at the earliest (hw_free
+ * would be too early).
+ *
+ * We are operating on a foreign cluster here, but since we
+ * belong to the same PCM, accesses should have been
+ * synchronized at ASoC level.
+ */
+ cl->clocks_in_use[substream->stream] = false;
+
+ if (!mca_fe_clocks_in_use(fe_cl))
+ mca_fe_disable_clocks(fe_cl);
+ }
+
cl->port_started[substream->stream] = false;
if (!mca_be_started(cl)) {
@@ -802,7 +795,6 @@ static void mca_be_shutdown(struct snd_pcm_substream *substream,
static const struct snd_soc_dai_ops mca_be_ops = {
.prepare = mca_be_prepare,
- .hw_free = mca_be_hw_free,
.startup = mca_be_startup,
.shutdown = mca_be_shutdown,
};
--
2.49.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 4/9] ASoC: apple: mca: Separate data & clock port setup
2025-05-18 10:50 [PATCH 0/9] ASoC: apple: mca: support simultaneous I2S capture on the frontend James Calligeros
` (2 preceding siblings ...)
2025-05-18 10:50 ` [PATCH 3/9] ASoC: apple: mca: Move clock shutdown to backend shutdown James Calligeros
@ 2025-05-18 10:50 ` James Calligeros
2025-05-18 10:50 ` [PATCH 5/9] ASoC: apple: mca: Factor out mca_be_get_fe James Calligeros
` (5 subsequent siblings)
9 siblings, 0 replies; 12+ messages in thread
From: James Calligeros @ 2025-05-18 10:50 UTC (permalink / raw)
To: Martin Povišer, Liam Girdwood, Mark Brown, Jaroslav Kysela,
Takashi Iwai
Cc: asahi, linux-sound, linux-kernel, James Calligeros
From: Martin Povišer <povik+lin@cutebit.org>
Up until now FEs were always the clock providers -- feeding the clocks
on any ports (BEs) they are attached to. This will soon change and FEs
will be allowed to be clock consumers. Once that happens, the routing
of clocks and data will to some degree decouple.
In advance of the change, make preparations:
* Narrow down semantics of what was formerly the 'port_driver' field
to refer to clocks only.
* On 'startup' of BEs, separate the clock and data aspects of the port
setup.
Signed-off-by: Martin Povišer <povik+lin@cutebit.org>
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
---
sound/soc/apple/mca.c | 67 +++++++++++++++----------
1 file changed, 40 insertions(+), 27 deletions(-)
diff --git a/sound/soc/apple/mca.c b/sound/soc/apple/mca.c
index 69f2e852d4aeb2d53eea5d7fee400b2337a09065..39713c378ba10910b0a3ac3d804844b25dfa2c94 100644
--- a/sound/soc/apple/mca.c
+++ b/sound/soc/apple/mca.c
@@ -134,8 +134,8 @@ struct mca_cluster {
struct clk *clk_parent;
struct dma_chan *dma_chans[SNDRV_PCM_STREAM_LAST + 1];
- bool port_started[SNDRV_PCM_STREAM_LAST + 1];
- int port_driver; /* The cluster driving this cluster's port */
+ bool port_clk_started[SNDRV_PCM_STREAM_LAST + 1];
+ int port_clk_driver; /* The cluster driving this cluster's port */
bool clocks_in_use[SNDRV_PCM_STREAM_LAST + 1];
struct device_link *pd_link;
@@ -158,7 +158,7 @@ struct mca_data {
struct reset_control *rstc;
struct device_link *pd_link;
- /* Mutex for accessing port_driver of foreign clusters */
+ /* Mutex for accessing port_clk_driver of foreign clusters */
struct mutex port_mutex;
int nclusters;
@@ -317,7 +317,7 @@ static bool mca_fe_clocks_in_use(struct mca_cluster *cl)
for (i = 0; i < mca->nclusters; i++) {
be_cl = &mca->clusters[i];
- if (be_cl->port_driver != cl->no)
+ if (be_cl->port_clk_driver != cl->no)
continue;
for_each_pcm_streams(stream) {
@@ -339,10 +339,10 @@ static int mca_be_prepare(struct snd_pcm_substream *substream,
struct mca_cluster *fe_cl;
int ret;
- if (cl->port_driver < 0)
+ if (cl->port_clk_driver < 0)
return -EINVAL;
- fe_cl = &mca->clusters[cl->port_driver];
+ fe_cl = &mca->clusters[cl->port_clk_driver];
/*
* Typically the CODECs we are paired with will require clocks
@@ -689,12 +689,15 @@ static const struct snd_soc_dai_ops mca_fe_ops = {
.trigger = mca_fe_trigger,
};
-static bool mca_be_started(struct mca_cluster *cl)
+/*
+ * Is there a FE attached which will be feeding this port's clocks?
+ */
+static bool mca_be_clk_started(struct mca_cluster *cl)
{
int stream;
for_each_pcm_streams(stream)
- if (cl->port_started[stream])
+ if (cl->port_clk_started[stream])
return true;
return false;
}
@@ -725,29 +728,35 @@ static int mca_be_startup(struct snd_pcm_substream *substream,
fe_cl = mca_dai_to_cluster(snd_soc_rtd_to_cpu(fe, 0));
- if (mca_be_started(cl)) {
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ writel_relaxed(PORT_DATA_SEL_TXA(fe_cl->no),
+ cl->base + REG_PORT_DATA_SEL);
+ mca_modify(cl, REG_PORT_ENABLES, PORT_ENABLES_TX_DATA,
+ PORT_ENABLES_TX_DATA);
+ }
+
+ if (mca_be_clk_started(cl)) {
/*
* Port is already started in the other direction.
* Make sure there isn't a conflict with another cluster
- * driving the port.
+ * driving the port clocks.
*/
- if (cl->port_driver != fe_cl->no)
+ if (cl->port_clk_driver != fe_cl->no)
return -EINVAL;
- cl->port_started[substream->stream] = true;
+ cl->port_clk_started[substream->stream] = true;
return 0;
}
- writel_relaxed(PORT_ENABLES_CLOCKS | PORT_ENABLES_TX_DATA,
- cl->base + REG_PORT_ENABLES);
writel_relaxed(FIELD_PREP(PORT_CLOCK_SEL, fe_cl->no + 1),
cl->base + REG_PORT_CLOCK_SEL);
- writel_relaxed(PORT_DATA_SEL_TXA(fe_cl->no),
- cl->base + REG_PORT_DATA_SEL);
+ mca_modify(cl, REG_PORT_ENABLES, PORT_ENABLES_CLOCKS,
+ PORT_ENABLES_CLOCKS);
+
mutex_lock(&mca->port_mutex);
- cl->port_driver = fe_cl->no;
+ cl->port_clk_driver = fe_cl->no;
mutex_unlock(&mca->port_mutex);
- cl->port_started[substream->stream] = true;
+ cl->port_clk_started[substream->stream] = true;
return 0;
}
@@ -759,8 +768,8 @@ static void mca_be_shutdown(struct snd_pcm_substream *substream,
struct mca_data *mca = cl->host;
if (cl->clocks_in_use[substream->stream] &&
- !WARN_ON(cl->port_driver < 0)) {
- struct mca_cluster *fe_cl = &mca->clusters[cl->port_driver];
+ !WARN_ON(cl->port_clk_driver < 0)) {
+ struct mca_cluster *fe_cl = &mca->clusters[cl->port_clk_driver];
/*
* Typically the CODECs we are paired with will require clocks
@@ -778,17 +787,21 @@ static void mca_be_shutdown(struct snd_pcm_substream *substream,
mca_fe_disable_clocks(fe_cl);
}
- cl->port_started[substream->stream] = false;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ mca_modify(cl, REG_PORT_ENABLES, PORT_ENABLES_TX_DATA, 0);
+ writel_relaxed(0, cl->base + REG_PORT_DATA_SEL);
+ }
- if (!mca_be_started(cl)) {
+ cl->port_clk_started[substream->stream] = false;
+ if (!mca_be_clk_started(cl)) {
/*
* Were we the last direction to shutdown?
- * Turn off the lights.
+ * Turn off the lights (clocks).
*/
- writel_relaxed(0, cl->base + REG_PORT_ENABLES);
- writel_relaxed(0, cl->base + REG_PORT_DATA_SEL);
+ mca_modify(cl, REG_PORT_ENABLES, PORT_ENABLES_CLOCKS, 0);
+ writel_relaxed(0, cl->base + REG_PORT_CLOCK_SEL);
mutex_lock(&mca->port_mutex);
- cl->port_driver = -1;
+ cl->port_clk_driver = -1;
mutex_unlock(&mca->port_mutex);
}
}
@@ -1094,7 +1107,7 @@ static int apple_mca_probe(struct platform_device *pdev)
cl->host = mca;
cl->no = i;
cl->base = base + CLUSTER_STRIDE * i;
- cl->port_driver = -1;
+ cl->port_clk_driver = -1;
cl->clk_parent = of_clk_get(pdev->dev.of_node, i);
if (IS_ERR(cl->clk_parent)) {
dev_err(&pdev->dev, "unable to obtain clock %d: %ld\n",
--
2.49.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 5/9] ASoC: apple: mca: Factor out mca_be_get_fe
2025-05-18 10:50 [PATCH 0/9] ASoC: apple: mca: support simultaneous I2S capture on the frontend James Calligeros
` (3 preceding siblings ...)
2025-05-18 10:50 ` [PATCH 4/9] ASoC: apple: mca: Separate data & clock port setup James Calligeros
@ 2025-05-18 10:50 ` James Calligeros
2025-05-18 10:50 ` [PATCH 6/9] ASoC: apple: mca: Support FEs being clock consumers James Calligeros
` (4 subsequent siblings)
9 siblings, 0 replies; 12+ messages in thread
From: James Calligeros @ 2025-05-18 10:50 UTC (permalink / raw)
To: Martin Povišer, Liam Girdwood, Mark Brown, Jaroslav Kysela,
Takashi Iwai
Cc: asahi, linux-sound, linux-kernel, James Calligeros
From: Martin Povišer <povik+lin@cutebit.org>
This is a function that we also want to use from within mca_be_shutdown,
so factor it out.
Signed-off-by: Martin Povišer <povik+lin@cutebit.org>
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
---
sound/soc/apple/mca.c | 31 ++++++++++++++-----------
1 file changed, 18 insertions(+), 13 deletions(-)
diff --git a/sound/soc/apple/mca.c b/sound/soc/apple/mca.c
index 39713c378ba10910b0a3ac3d804844b25dfa2c94..7c3e1eae8b963ff593fdcf54e4a1f2e5f64a63c1 100644
--- a/sound/soc/apple/mca.c
+++ b/sound/soc/apple/mca.c
@@ -702,30 +702,35 @@ static bool mca_be_clk_started(struct mca_cluster *cl)
return false;
}
-static int mca_be_startup(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
+static struct snd_soc_pcm_runtime *mca_be_get_fe(struct snd_soc_pcm_runtime *be,
+ int stream)
{
- struct snd_soc_pcm_runtime *be = snd_soc_substream_to_rtd(substream);
- struct snd_soc_pcm_runtime *fe;
- struct mca_cluster *cl = mca_dai_to_cluster(dai);
- struct mca_cluster *fe_cl;
- struct mca_data *mca = cl->host;
+ struct snd_soc_pcm_runtime *fe = NULL;
struct snd_soc_dpcm *dpcm;
- fe = NULL;
-
- for_each_dpcm_fe(be, substream->stream, dpcm) {
+ for_each_dpcm_fe(be, stream, dpcm) {
if (fe && dpcm->fe != fe) {
- dev_err(mca->dev, "many FE per one BE unsupported\n");
- return -EINVAL;
+ dev_err(be->dev, "many FE per one BE unsupported\n");
+ return NULL;
}
fe = dpcm->fe;
}
+ return fe;
+}
+
+static int mca_be_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *be = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *fe = mca_be_get_fe(be, substream->stream);
+ struct mca_cluster *cl = mca_dai_to_cluster(dai);
+ struct mca_cluster *fe_cl;
+ struct mca_data *mca = cl->host;
+
if (!fe)
return -EINVAL;
-
fe_cl = mca_dai_to_cluster(snd_soc_rtd_to_cpu(fe, 0));
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
--
2.49.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 6/9] ASoC: apple: mca: Support FEs being clock consumers
2025-05-18 10:50 [PATCH 0/9] ASoC: apple: mca: support simultaneous I2S capture on the frontend James Calligeros
` (4 preceding siblings ...)
2025-05-18 10:50 ` [PATCH 5/9] ASoC: apple: mca: Factor out mca_be_get_fe James Calligeros
@ 2025-05-18 10:50 ` James Calligeros
2025-05-18 10:50 ` [PATCH 7/9] ASoC: apple: mca: Support capture on multiples BEs James Calligeros
` (3 subsequent siblings)
9 siblings, 0 replies; 12+ messages in thread
From: James Calligeros @ 2025-05-18 10:50 UTC (permalink / raw)
To: Martin Povišer, Liam Girdwood, Mark Brown, Jaroslav Kysela,
Takashi Iwai
Cc: asahi, linux-sound, linux-kernel, James Calligeros
From: Martin Povišer <povik+lin@cutebit.org>
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>
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
---
sound/soc/apple/mca.c | 125 ++++++++++++++++++++-----
1 file changed, 104 insertions(+), 21 deletions(-)
diff --git a/sound/soc/apple/mca.c b/sound/soc/apple/mca.c
index 7c3e1eae8b963ff593fdcf54e4a1f2e5f64a63c1..be6ff55203121808463846bebda682cdd97fc42d 100644
--- a/sound/soc/apple/mca.c
+++ b/sound/soc/apple/mca.c
@@ -134,12 +134,17 @@ struct mca_cluster {
struct clk *clk_parent;
struct dma_chan *dma_chans[SNDRV_PCM_STREAM_LAST + 1];
+ bool clk_provider;
+
bool port_clk_started[SNDRV_PCM_STREAM_LAST + 1];
int port_clk_driver; /* The cluster driving this cluster's port */
bool clocks_in_use[SNDRV_PCM_STREAM_LAST + 1];
struct device_link *pd_link;
+ /* In case of clock consumer FE */
+ int syncgen_in_use;
+
unsigned int bclk_ratio;
/* Masks etc. picked up via the set_tdm_slot method */
@@ -262,11 +267,32 @@ static int mca_fe_trigger(struct snd_pcm_substream *substream, int cmd,
return 0;
}
+static int mca_fe_get_port(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *fe = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *be;
+ struct snd_soc_dpcm *dpcm;
+
+ be = NULL;
+ for_each_dpcm_be(fe, substream->stream, dpcm) {
+ be = dpcm->be;
+ break;
+ }
+
+ if (!be)
+ return -EINVAL;
+
+ return mca_dai_to_cluster(snd_soc_rtd_to_cpu(be, 0))->no;
+}
+
static int mca_fe_enable_clocks(struct mca_cluster *cl)
{
struct mca_data *mca = cl->host;
int ret;
+ if (!cl->clk_provider)
+ return -EINVAL;
+
ret = clk_prepare_enable(cl->clk_parent);
if (ret) {
dev_err(mca->dev,
@@ -340,7 +366,7 @@ static int mca_be_prepare(struct snd_pcm_substream *substream,
int ret;
if (cl->port_clk_driver < 0)
- return -EINVAL;
+ return 0;
fe_cl = &mca->clusters[cl->port_clk_driver];
@@ -361,6 +387,57 @@ static int mca_be_prepare(struct snd_pcm_substream *substream,
return 0;
}
+static int mca_fe_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mca_cluster *cl = mca_dai_to_cluster(dai);
+ struct mca_data *mca = cl->host;
+
+ if (cl->clk_provider)
+ return 0;
+
+ /* Turn on the cluster power domain if not already in use */
+ if (!cl->syncgen_in_use) {
+ int port = mca_fe_get_port(substream);
+
+ cl->pd_link = device_link_add(mca->dev, cl->pd_dev,
+ DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME |
+ DL_FLAG_RPM_ACTIVE);
+ if (!cl->pd_link) {
+ dev_err(mca->dev,
+ "cluster %d: unable to prop-up power domain\n", cl->no);
+ return -EINVAL;
+ }
+
+ writel_relaxed(port + 6 + 1,
+ cl->base + REG_SYNCGEN_MCLK_SEL);
+ mca_modify(cl, REG_SYNCGEN_STATUS, SYNCGEN_STATUS_EN,
+ SYNCGEN_STATUS_EN);
+ }
+ cl->syncgen_in_use |= 1 << substream->stream;
+
+ return 0;
+}
+
+static int mca_fe_hw_free(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct mca_cluster *cl = mca_dai_to_cluster(dai);
+
+ if (cl->clk_provider)
+ return 0;
+
+ cl->syncgen_in_use &= ~(1 << substream->stream);
+ if (cl->syncgen_in_use)
+ return 0;
+
+ mca_modify(cl, REG_SYNCGEN_STATUS, SYNCGEN_STATUS_EN, 0);
+ if (cl->pd_link)
+ device_link_del(cl->pd_link);
+
+ return 0;
+}
+
static unsigned int mca_crop_mask(unsigned int mask, int nchans)
{
while (hweight32(mask) > nchans)
@@ -486,9 +563,18 @@ static int mca_fe_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
u32 serdes_conf = 0;
u32 bitstart;
- if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) !=
- SND_SOC_DAIFMT_BP_FP)
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
+ case SND_SOC_DAIFMT_BP_FP:
+ cl->clk_provider = true;
+ break;
+
+ case SND_SOC_DAIFMT_BC_FC:
+ cl->clk_provider = false;
+ break;
+
+ default:
goto err;
+ }
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
@@ -545,24 +631,6 @@ static int mca_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
return 0;
}
-static int mca_fe_get_port(struct snd_pcm_substream *substream)
-{
- struct snd_soc_pcm_runtime *fe = snd_soc_substream_to_rtd(substream);
- struct snd_soc_pcm_runtime *be;
- struct snd_soc_dpcm *dpcm;
-
- be = NULL;
- for_each_dpcm_be(fe, substream->stream, dpcm) {
- be = dpcm->be;
- break;
- }
-
- if (!be)
- return -EINVAL;
-
- return mca_dai_to_cluster(snd_soc_rtd_to_cpu(be, 0))->no;
-}
-
static int mca_fe_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
@@ -687,6 +755,8 @@ static const struct snd_soc_dai_ops mca_fe_ops = {
.set_tdm_slot = mca_fe_set_tdm_slot,
.hw_params = mca_fe_hw_params,
.trigger = mca_fe_trigger,
+ .prepare = mca_fe_prepare,
+ .hw_free = mca_fe_hw_free,
};
/*
@@ -740,6 +810,9 @@ static int mca_be_startup(struct snd_pcm_substream *substream,
PORT_ENABLES_TX_DATA);
}
+ if (!fe_cl->clk_provider)
+ return 0;
+
if (mca_be_clk_started(cl)) {
/*
* Port is already started in the other direction.
@@ -769,7 +842,10 @@ static int mca_be_startup(struct snd_pcm_substream *substream,
static void mca_be_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
+ struct snd_soc_pcm_runtime *be = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *fe = mca_be_get_fe(be, substream->stream);
struct mca_cluster *cl = mca_dai_to_cluster(dai);
+ struct mca_cluster *fe_cl;
struct mca_data *mca = cl->host;
if (cl->clocks_in_use[substream->stream] &&
@@ -792,11 +868,18 @@ static void mca_be_shutdown(struct snd_pcm_substream *substream,
mca_fe_disable_clocks(fe_cl);
}
+ if (!fe)
+ return;
+ fe_cl = mca_dai_to_cluster(snd_soc_rtd_to_cpu(fe, 0));
+
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
mca_modify(cl, REG_PORT_ENABLES, PORT_ENABLES_TX_DATA, 0);
writel_relaxed(0, cl->base + REG_PORT_DATA_SEL);
}
+ if (!fe_cl->clk_provider)
+ return;
+
cl->port_clk_started[substream->stream] = false;
if (!mca_be_clk_started(cl)) {
/*
--
2.49.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 7/9] ASoC: apple: mca: Support capture on multiples BEs
2025-05-18 10:50 [PATCH 0/9] ASoC: apple: mca: support simultaneous I2S capture on the frontend James Calligeros
` (5 preceding siblings ...)
2025-05-18 10:50 ` [PATCH 6/9] ASoC: apple: mca: Support FEs being clock consumers James Calligeros
@ 2025-05-18 10:50 ` James Calligeros
2025-05-18 10:50 ` [PATCH 8/9] ASoC: apple: mca: Do not mark clocks in use for non-providers James Calligeros
` (2 subsequent siblings)
9 siblings, 0 replies; 12+ messages in thread
From: James Calligeros @ 2025-05-18 10:50 UTC (permalink / raw)
To: Martin Povišer, Liam Girdwood, Mark Brown, Jaroslav Kysela,
Takashi Iwai
Cc: asahi, linux-sound, linux-kernel, James Calligeros
From: Martin Povišer <povik+lin@cutebit.org>
When multiple BEs are linked to a FE, the former behavior was to source
the data line from the DIN pin of the first BE only. Change this to
ORing the DIN inputs of all linked BEs.
As long as the unused slots on each BE's line are zeroed out and the
slots on the BEs don't overlap, this will work out well.
Signed-off-by: Martin Povišer <povik+lin@cutebit.org>
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
---
sound/soc/apple/mca.c | 31 +++++++++++--------------
1 file changed, 14 insertions(+), 17 deletions(-)
diff --git a/sound/soc/apple/mca.c b/sound/soc/apple/mca.c
index be6ff55203121808463846bebda682cdd97fc42d..441da5ef3de1c0be1dc607ff2490046206660e59 100644
--- a/sound/soc/apple/mca.c
+++ b/sound/soc/apple/mca.c
@@ -267,22 +267,19 @@ static int mca_fe_trigger(struct snd_pcm_substream *substream, int cmd,
return 0;
}
-static int mca_fe_get_port(struct snd_pcm_substream *substream)
+static int mca_fe_get_portmask(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *fe = snd_soc_substream_to_rtd(substream);
- struct snd_soc_pcm_runtime *be;
struct snd_soc_dpcm *dpcm;
+ int mask = 0;
- be = NULL;
for_each_dpcm_be(fe, substream->stream, dpcm) {
- be = dpcm->be;
- break;
- }
+ int no = mca_dai_to_cluster(snd_soc_rtd_to_cpu(dpcm->be, 0))->no;
- if (!be)
- return -EINVAL;
+ mask |= 1 << no;
+ }
- return mca_dai_to_cluster(snd_soc_rtd_to_cpu(be, 0))->no;
+ return mask;
}
static int mca_fe_enable_clocks(struct mca_cluster *cl)
@@ -398,7 +395,7 @@ static int mca_fe_prepare(struct snd_pcm_substream *substream,
/* Turn on the cluster power domain if not already in use */
if (!cl->syncgen_in_use) {
- int port = mca_fe_get_port(substream);
+ int port = ffs(mca_fe_get_portmask(substream)) - 1;
cl->pd_link = device_link_add(mca->dev, cl->pd_dev,
DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME |
@@ -448,7 +445,7 @@ static unsigned int mca_crop_mask(unsigned int mask, int nchans)
static int mca_configure_serdes(struct mca_cluster *cl, int serdes_unit,
unsigned int mask, int slots, int nchans,
- int slot_width, bool is_tx, int port)
+ int slot_width, bool is_tx, int portmask)
{
__iomem void *serdes_base = cl->base + serdes_unit;
u32 serdes_conf, serdes_conf_mask;
@@ -507,7 +504,7 @@ static int mca_configure_serdes(struct mca_cluster *cl, int serdes_unit,
serdes_base + REG_RX_SERDES_SLOTMASK);
writel_relaxed(~((u32)mca_crop_mask(mask, nchans)),
serdes_base + REG_RX_SERDES_SLOTMASK + 0x4);
- writel_relaxed(1 << port,
+ writel_relaxed(portmask,
serdes_base + REG_RX_SERDES_PORT);
}
@@ -644,7 +641,7 @@ static int mca_fe_hw_params(struct snd_pcm_substream *substream,
unsigned long bclk_ratio;
unsigned int tdm_slots, tdm_slot_width, tdm_mask;
u32 regval, pad;
- int ret, port, nchans_ceiled;
+ int ret, portmask, nchans_ceiled;
if (!cl->tdm_slot_width) {
/*
@@ -693,13 +690,13 @@ static int mca_fe_hw_params(struct snd_pcm_substream *substream,
tdm_mask = (1 << tdm_slots) - 1;
}
- port = mca_fe_get_port(substream);
- if (port < 0)
- return port;
+ portmask = mca_fe_get_portmask(substream);
+ if (!portmask)
+ return -EINVAL;
ret = mca_configure_serdes(cl, is_tx ? CLUSTER_TX_OFF : CLUSTER_RX_OFF,
tdm_mask, tdm_slots, params_channels(params),
- tdm_slot_width, is_tx, port);
+ tdm_slot_width, is_tx, portmask);
if (ret)
return ret;
--
2.49.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 8/9] ASoC: apple: mca: Do not mark clocks in use for non-providers
2025-05-18 10:50 [PATCH 0/9] ASoC: apple: mca: support simultaneous I2S capture on the frontend James Calligeros
` (6 preceding siblings ...)
2025-05-18 10:50 ` [PATCH 7/9] ASoC: apple: mca: Support capture on multiples BEs James Calligeros
@ 2025-05-18 10:50 ` James Calligeros
2025-05-18 10:50 ` [PATCH 9/9] ASoC: apple: mca: Add delay after configuring clock James Calligeros
2025-05-20 9:20 ` (subset) [PATCH 0/9] ASoC: apple: mca: support simultaneous I2S capture on the frontend Mark Brown
9 siblings, 0 replies; 12+ messages in thread
From: James Calligeros @ 2025-05-18 10:50 UTC (permalink / raw)
To: Martin Povišer, Liam Girdwood, Mark Brown, Jaroslav Kysela,
Takashi Iwai
Cc: asahi, linux-sound, linux-kernel, Hector Martin, James Calligeros
From: Hector Martin <marcan@marcan.st>
On the speakers PCM, this sequence:
1. Open playback
2. Open sense
3. Close playback
4. Close sense
would result in the sense FE being marked as clocks in use at (2), since
there is a clock provider (playback FE). Then at (4) this would WARN since
there is no driver any more when closing the in use clocks.
If (1) and (2) are reversed this does not happen, since the sense PCM is
not marked as using the clocks when there is no provider yet. So, check
explicitly whether the substream FE is a clock provider in be_prepare,
and skip everything if it isn't.
Signed-off-by: Hector Martin <marcan@marcan.st>
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
---
sound/soc/apple/mca.c | 67 ++++++++++++++-----------
1 file changed, 37 insertions(+), 30 deletions(-)
diff --git a/sound/soc/apple/mca.c b/sound/soc/apple/mca.c
index 441da5ef3de1c0be1dc607ff2490046206660e59..25d04b3d8a57a8551f2ac1c0cd2dbf2997d907e8 100644
--- a/sound/soc/apple/mca.c
+++ b/sound/soc/apple/mca.c
@@ -354,36 +354,6 @@ static bool mca_fe_clocks_in_use(struct mca_cluster *cl)
return false;
}
-static int mca_be_prepare(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct mca_cluster *cl = mca_dai_to_cluster(dai);
- struct mca_data *mca = cl->host;
- struct mca_cluster *fe_cl;
- int ret;
-
- if (cl->port_clk_driver < 0)
- return 0;
-
- fe_cl = &mca->clusters[cl->port_clk_driver];
-
- /*
- * Typically the CODECs we are paired with will require clocks
- * to be present at time of unmute with the 'mute_stream' op
- * or at time of DAPM widget power-up. We need to enable clocks
- * here at the latest (frontend prepare would be too late).
- */
- if (!mca_fe_clocks_in_use(fe_cl)) {
- ret = mca_fe_enable_clocks(fe_cl);
- if (ret < 0)
- return ret;
- }
-
- cl->clocks_in_use[substream->stream] = true;
-
- return 0;
-}
-
static int mca_fe_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
@@ -787,6 +757,43 @@ static struct snd_soc_pcm_runtime *mca_be_get_fe(struct snd_soc_pcm_runtime *be,
return fe;
}
+static int mca_be_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *be = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *fe = mca_be_get_fe(be, substream->stream);
+ struct mca_cluster *cl = mca_dai_to_cluster(dai);
+ struct mca_data *mca = cl->host;
+ struct mca_cluster *fe_cl, *fe_clk_cl;
+ int ret;
+
+ fe_cl = mca_dai_to_cluster(snd_soc_rtd_to_cpu(fe, 0));
+
+ if (!fe_cl->clk_provider)
+ return 0;
+
+ if (cl->port_clk_driver < 0)
+ return 0;
+
+ fe_clk_cl = &mca->clusters[cl->port_clk_driver];
+
+ /*
+ * Typically the CODECs we are paired with will require clocks
+ * to be present at time of unmute with the 'mute_stream' op
+ * or at time of DAPM widget power-up. We need to enable clocks
+ * here at the latest (frontend prepare would be too late).
+ */
+ if (!mca_fe_clocks_in_use(fe_clk_cl)) {
+ ret = mca_fe_enable_clocks(fe_clk_cl);
+ if (ret < 0)
+ return ret;
+ }
+
+ cl->clocks_in_use[substream->stream] = true;
+
+ return 0;
+}
+
static int mca_be_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
--
2.49.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 9/9] ASoC: apple: mca: Add delay after configuring clock
2025-05-18 10:50 [PATCH 0/9] ASoC: apple: mca: support simultaneous I2S capture on the frontend James Calligeros
` (7 preceding siblings ...)
2025-05-18 10:50 ` [PATCH 8/9] ASoC: apple: mca: Do not mark clocks in use for non-providers James Calligeros
@ 2025-05-18 10:50 ` James Calligeros
2025-05-20 9:20 ` (subset) [PATCH 0/9] ASoC: apple: mca: support simultaneous I2S capture on the frontend Mark Brown
9 siblings, 0 replies; 12+ messages in thread
From: James Calligeros @ 2025-05-18 10:50 UTC (permalink / raw)
To: Martin Povišer, Liam Girdwood, Mark Brown, Jaroslav Kysela,
Takashi Iwai
Cc: asahi, linux-sound, linux-kernel, Hector Martin, James Calligeros
From: Hector Martin <marcan@marcan.st>
Right after the early FE setup, ADMAC gets told to start the DMA. This
can end up in a weird "slip" state with the channels transposed. Waiting
a bit fixes this; presumably this allows the clock to stabilize.
Signed-off-by: Hector Martin <marcan@marcan.st>
Signed-off-by: James Calligeros <jcalligeros99@gmail.com>
---
sound/soc/apple/mca.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/sound/soc/apple/mca.c b/sound/soc/apple/mca.c
index 25d04b3d8a57a8551f2ac1c0cd2dbf2997d907e8..1c664c204504174df1d0af3cafbe25235c678687 100644
--- a/sound/soc/apple/mca.c
+++ b/sound/soc/apple/mca.c
@@ -231,6 +231,12 @@ static void mca_fe_early_trigger(struct snd_pcm_substream *substream, int cmd,
FIELD_PREP(SERDES_CONF_SYNC_SEL, 0));
mca_modify(cl, serdes_conf, SERDES_CONF_SYNC_SEL,
FIELD_PREP(SERDES_CONF_SYNC_SEL, cl->no + 1));
+ /*
+ * ADMAC gets started right after this. This delay seems
+ * to be needed for that to be reliable, e.g. ensure the
+ * clock is stable?
+ */
+ udelay(100);
break;
default:
break;
--
2.49.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH 3/9] ASoC: apple: mca: Move clock shutdown to backend shutdown
2025-05-18 10:50 ` [PATCH 3/9] ASoC: apple: mca: Move clock shutdown to backend shutdown James Calligeros
@ 2025-05-19 10:38 ` Mark Brown
0 siblings, 0 replies; 12+ messages in thread
From: Mark Brown @ 2025-05-19 10:38 UTC (permalink / raw)
To: James Calligeros
Cc: Martin Povišer, Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
asahi, linux-sound, linux-kernel, Hector Martin
[-- Attachment #1: Type: text/plain, Size: 565 bytes --]
On Sun, May 18, 2025 at 08:50:48PM +1000, James Calligeros wrote:
> From: Hector Martin <marcan@marcan.st>
>
> Codecs are set to mute after hw_free, so yanking the clock out from
> under them in hw_free leads to breakage. Move the clock shutdown to the
> shutdown op, which is late enough.
The mute should be the first thing that happens, before we do the DAPM
stream stop event or hw_free() for precisely this reason? See
soc_pcm_hw_clean(). The reason we do the mute is to cover any glitches
introduced into the stream during the teardown process.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: (subset) [PATCH 0/9] ASoC: apple: mca: support simultaneous I2S capture on the frontend
2025-05-18 10:50 [PATCH 0/9] ASoC: apple: mca: support simultaneous I2S capture on the frontend James Calligeros
` (8 preceding siblings ...)
2025-05-18 10:50 ` [PATCH 9/9] ASoC: apple: mca: Add delay after configuring clock James Calligeros
@ 2025-05-20 9:20 ` Mark Brown
9 siblings, 0 replies; 12+ messages in thread
From: Mark Brown @ 2025-05-20 9:20 UTC (permalink / raw)
To: Martin Povišer, Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
James Calligeros
Cc: asahi, linux-sound, linux-kernel, Hector Martin
On Sun, 18 May 2025 20:50:45 +1000, James Calligeros wrote:
> This series introduces a number of changes to the ASoC driver
> for the Apple MCA peripheral to enable support for bidirectional
> I2S. This is achieved by allowing frontends to act as clock consumers
> and logically ORing data input lines when multiple backends are linked
> to a frontend.
>
> This allows the Texas Instruments speaker amps used on Apple Silicon Macs
> (Apple-specific revisions of TAS2764 and TAS2770) to send their IVSENSE
> data back to the SoC. Since these amps do not have any sort of integrated
> speaker protection logic, we must use the IVSENSE data and the Thiele/Small
> Parameters of the attached speaker(s) to implement our own in software.
>
> [...]
Applied to
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next
Thanks!
[1/9] ASoC: apple: mca: Constrain channels according to TDM mask
commit: e717c661e2d1a660e96c40b0fe9933e23a1d7747
[2/9] ASoC: apple: mca: use readx_poll_timeout to check for cluster reset
(no commit info)
[4/9] ASoC: apple: mca: Separate data & clock port setup
(no commit info)
[5/9] ASoC: apple: mca: Factor out mca_be_get_fe
(no commit info)
[6/9] ASoC: apple: mca: Support FEs being clock consumers
(no commit info)
[7/9] ASoC: apple: mca: Support capture on multiples BEs
(no commit info)
[8/9] ASoC: apple: mca: Do not mark clocks in use for non-providers
(no commit info)
[9/9] ASoC: apple: mca: Add delay after configuring clock
(no commit info)
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2025-05-20 9:20 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-05-18 10:50 [PATCH 0/9] ASoC: apple: mca: support simultaneous I2S capture on the frontend James Calligeros
2025-05-18 10:50 ` [PATCH 1/9] ASoC: apple: mca: Constrain channels according to TDM mask James Calligeros
2025-05-18 10:50 ` [PATCH 2/9] ASoC: apple: mca: use readx_poll_timeout to check for cluster reset James Calligeros
2025-05-18 10:50 ` [PATCH 3/9] ASoC: apple: mca: Move clock shutdown to backend shutdown James Calligeros
2025-05-19 10:38 ` Mark Brown
2025-05-18 10:50 ` [PATCH 4/9] ASoC: apple: mca: Separate data & clock port setup James Calligeros
2025-05-18 10:50 ` [PATCH 5/9] ASoC: apple: mca: Factor out mca_be_get_fe James Calligeros
2025-05-18 10:50 ` [PATCH 6/9] ASoC: apple: mca: Support FEs being clock consumers James Calligeros
2025-05-18 10:50 ` [PATCH 7/9] ASoC: apple: mca: Support capture on multiples BEs James Calligeros
2025-05-18 10:50 ` [PATCH 8/9] ASoC: apple: mca: Do not mark clocks in use for non-providers James Calligeros
2025-05-18 10:50 ` [PATCH 9/9] ASoC: apple: mca: Add delay after configuring clock James Calligeros
2025-05-20 9:20 ` (subset) [PATCH 0/9] ASoC: apple: mca: support simultaneous I2S capture on the frontend Mark Brown
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).