summaryrefslogtreecommitdiff
path: root/sound/soc/apple/mca.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/apple/mca.c')
-rw-r--r--sound/soc/apple/mca.c88
1 files changed, 63 insertions, 25 deletions
diff --git a/sound/soc/apple/mca.c b/sound/soc/apple/mca.c
index 24381c42eb54..c4dcb2b54591 100644
--- a/sound/soc/apple/mca.c
+++ b/sound/soc/apple/mca.c
@@ -101,7 +101,6 @@
#define SERDES_CONF_UNK3 BIT(14)
#define SERDES_CONF_NO_DATA_FEEDBACK BIT(15)
#define SERDES_CONF_SYNC_SEL GENMASK(18, 16)
-#define SERDES_CONF_SOME_RST BIT(19)
#define REG_TX_SERDES_BITSTART 0x08
#define REG_RX_SERDES_BITSTART 0x0c
#define REG_TX_SERDES_SLOTMASK 0x0c
@@ -162,7 +161,7 @@ struct mca_data {
struct mutex port_mutex;
int nclusters;
- struct mca_cluster clusters[];
+ struct mca_cluster clusters[] __counted_by(nclusters);
};
static void mca_modify(struct mca_cluster *cl, int regoffset, u32 mask, u32 val)
@@ -203,15 +202,24 @@ static void mca_fe_early_trigger(struct snd_pcm_substream *substream, int cmd,
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ 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,
+ FIELD_PREP(SERDES_CONF_SYNC_SEL, 7));
mca_modify(cl, serdes_unit + REG_SERDES_STATUS,
SERDES_STATUS_EN | SERDES_STATUS_RST,
SERDES_STATUS_RST);
- mca_modify(cl, serdes_conf, SERDES_CONF_SOME_RST,
- SERDES_CONF_SOME_RST);
- readl_relaxed(cl->base + serdes_conf);
- mca_modify(cl, serdes_conf, SERDES_STATUS_RST, 0);
- WARN_ON(readl_relaxed(cl->base + REG_SERDES_STATUS) &
+ /*
+ * Experiments suggest that it takes at most ~1 us
+ * for the bit to clear, so wait 2 us for good measure.
+ */
+ udelay(2);
+ WARN_ON(readl_relaxed(cl->base + serdes_unit + REG_SERDES_STATUS) &
SERDES_STATUS_RST);
+ 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,
+ FIELD_PREP(SERDES_CONF_SYNC_SEL, cl->no + 1));
break;
default:
break;
@@ -456,6 +464,28 @@ err:
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)
{
@@ -538,7 +568,7 @@ static int mca_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
static int mca_fe_get_port(struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *fe = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *fe = snd_soc_substream_to_rtd(substream);
struct snd_soc_pcm_runtime *be;
struct snd_soc_dpcm *dpcm;
@@ -551,7 +581,7 @@ static int mca_fe_get_port(struct snd_pcm_substream *substream)
if (!be)
return -EINVAL;
- return mca_dai_to_cluster(asoc_rtd_to_cpu(be, 0))->no;
+ return mca_dai_to_cluster(snd_soc_rtd_to_cpu(be, 0))->no;
}
static int mca_fe_hw_params(struct snd_pcm_substream *substream,
@@ -608,7 +638,7 @@ static int mca_fe_hw_params(struct snd_pcm_substream *substream,
tdm_slot_width = 32;
if (tdm_slot_width < params_width(params)) {
- dev_err(dev, "TDM slots too narrow (tdm=%d params=%d)\n",
+ dev_err(dev, "TDM slots too narrow (tdm=%u params=%d)\n",
tdm_slot_width, params_width(params));
return -EINVAL;
}
@@ -672,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,
@@ -692,7 +723,7 @@ static bool mca_be_started(struct mca_cluster *cl)
static int mca_be_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *be = asoc_substream_to_rtd(substream);
+ 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;
@@ -713,7 +744,7 @@ static int mca_be_startup(struct snd_pcm_substream *substream,
if (!fe)
return -EINVAL;
- fe_cl = mca_dai_to_cluster(asoc_rtd_to_cpu(fe, 0));
+ fe_cl = mca_dai_to_cluster(snd_soc_rtd_to_cpu(fe, 0));
if (mca_be_started(cl)) {
/*
@@ -803,8 +834,8 @@ static int mca_set_runtime_hwparams(struct snd_soc_component *component,
static int mca_pcm_open(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
- struct mca_cluster *cl = mca_dai_to_cluster(asoc_rtd_to_cpu(rtd, 0));
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct mca_cluster *cl = mca_dai_to_cluster(snd_soc_rtd_to_cpu(rtd, 0));
struct dma_chan *chan = cl->dma_chans[substream->stream];
int ret;
@@ -822,7 +853,7 @@ static int mca_hw_params(struct snd_soc_component *component,
struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
struct dma_slave_config slave_config;
int ret;
@@ -849,7 +880,7 @@ static int mca_hw_params(struct snd_soc_component *component,
static int mca_close(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
if (rtd->dai_link->no_pcm)
return 0;
@@ -860,7 +891,7 @@ static int mca_close(struct snd_soc_component *component,
static int mca_trigger(struct snd_soc_component *component,
struct snd_pcm_substream *substream, int cmd)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
if (rtd->dai_link->no_pcm)
return 0;
@@ -869,7 +900,7 @@ static int mca_trigger(struct snd_soc_component *component,
* Before we do the PCM trigger proper, insert an opportunity
* to reset the frontend's SERDES.
*/
- mca_fe_early_trigger(substream, cmd, asoc_rtd_to_cpu(rtd, 0));
+ mca_fe_early_trigger(substream, cmd, snd_soc_rtd_to_cpu(rtd, 0));
return snd_dmaengine_pcm_trigger(substream, cmd);
}
@@ -877,7 +908,7 @@ static int mca_trigger(struct snd_soc_component *component,
static snd_pcm_uframes_t mca_pointer(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
- struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
if (rtd->dai_link->no_pcm)
return -ENOTSUPP;
@@ -903,7 +934,7 @@ static void mca_pcm_free(struct snd_soc_component *component,
struct snd_pcm *pcm)
{
struct snd_soc_pcm_runtime *rtd = snd_pcm_chip(pcm);
- struct mca_cluster *cl = mca_dai_to_cluster(asoc_rtd_to_cpu(rtd, 0));
+ struct mca_cluster *cl = mca_dai_to_cluster(snd_soc_rtd_to_cpu(rtd, 0));
unsigned int i;
if (rtd->dai_link->no_pcm)
@@ -925,7 +956,7 @@ static void mca_pcm_free(struct snd_soc_component *component,
static int mca_pcm_new(struct snd_soc_component *component,
struct snd_soc_pcm_runtime *rtd)
{
- struct mca_cluster *cl = mca_dai_to_cluster(asoc_rtd_to_cpu(rtd, 0));
+ struct mca_cluster *cl = mca_dai_to_cluster(snd_soc_rtd_to_cpu(rtd, 0));
unsigned int i;
if (rtd->dai_link->no_pcm)
@@ -942,10 +973,17 @@ static int mca_pcm_new(struct snd_soc_component *component,
chan = mca_request_dma_channel(cl, i);
if (IS_ERR_OR_NULL(chan)) {
+ mca_pcm_free(component, rtd->pcm);
+
+ if (chan && PTR_ERR(chan) == -EPROBE_DEFER)
+ return PTR_ERR(chan);
+
dev_err(component->dev, "unable to obtain DMA channel (stream %d cluster %d): %pe\n",
i, cl->no, chan);
- mca_pcm_free(component, rtd->pcm);
- return -EINVAL;
+
+ if (!chan)
+ return -EINVAL;
+ return PTR_ERR(chan);
}
cl->dma_chans[i] = chan;
@@ -1144,16 +1182,16 @@ err_release:
return ret;
}
-static int apple_mca_remove(struct platform_device *pdev)
+static void apple_mca_remove(struct platform_device *pdev)
{
struct mca_data *mca = platform_get_drvdata(pdev);
snd_soc_unregister_component(&pdev->dev);
apple_mca_release(mca);
- return 0;
}
static const struct of_device_id apple_mca_of_match[] = {
+ { .compatible = "apple,t8103-mca", },
{ .compatible = "apple,mca", },
{}
};