diff options
Diffstat (limited to 'sound/soc/apple/mca.c')
| -rw-r--r-- | sound/soc/apple/mca.c | 88 |
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", }, {} }; |
