static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai); bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; u8 i, channels = substream->runtime->channels; u32 pins = DIV_ROUND_UP(channels, esai_priv->slots); u32 mask; switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), ESAI_xFCR_xFEN_MASK, ESAI_xFCR_xFEN); /* Write initial words reqiured by ESAI as normal procedure */ for (i = 0; tx && i < channels; i++) regmap_write(esai_priv->regmap, REG_ESAI_ETDR, 0x0); regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK, tx ? ESAI_xCR_TE(pins) : ESAI_xCR_RE(pins)); mask = tx ? esai_priv->tx_mask : esai_priv->rx_mask; regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMA(tx), ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(mask)); regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMB(tx), ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(mask)); break; case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK, 0); regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMA(tx), ESAI_xSMA_xS_MASK, 0); regmap_update_bits(esai_priv->regmap, REG_ESAI_xSMB(tx), ESAI_xSMB_xS_MASK, 0); /* Disable and reset FIFO */ regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), ESAI_xFCR_xFR | ESAI_xFCR_xFEN, ESAI_xFCR_xFR); regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), ESAI_xFCR_xFR, 0); break; default: return -EINVAL; } return 0; }
static int fsl_esai_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai); bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; u32 width = params_width(params); u32 channels = params_channels(params); u32 pins = DIV_ROUND_UP(channels, esai_priv->slots); u32 slot_width = width; u32 bclk, mask, val; int ret; /* Override slot_width if being specifically set */ if (esai_priv->slot_width) slot_width = esai_priv->slot_width; bclk = params_rate(params) * slot_width * esai_priv->slots; ret = fsl_esai_set_bclk(dai, tx, bclk); if (ret) return ret; /* Use Normal mode to support monaural audio */ regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), ESAI_xCR_xMOD_MASK, params_channels(params) > 1 ? ESAI_xCR_xMOD_NETWORK : 0); regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), ESAI_xFCR_xFR_MASK, ESAI_xFCR_xFR); mask = ESAI_xFCR_xFR_MASK | ESAI_xFCR_xWA_MASK | ESAI_xFCR_xFWM_MASK | (tx ? ESAI_xFCR_TE_MASK | ESAI_xFCR_TIEN : ESAI_xFCR_RE_MASK); val = ESAI_xFCR_xWA(width) | ESAI_xFCR_xFWM(esai_priv->fifo_depth) | (tx ? ESAI_xFCR_TE(pins) | ESAI_xFCR_TIEN : ESAI_xFCR_RE(pins)); regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), mask, val); mask = ESAI_xCR_xSWS_MASK | (tx ? ESAI_xCR_PADC : 0); val = ESAI_xCR_xSWS(slot_width, width) | (tx ? ESAI_xCR_PADC : 0); regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), mask, val); /* Remove ESAI personal reset by configuring ESAI_PCRC and ESAI_PRRC */ regmap_update_bits(esai_priv->regmap, REG_ESAI_PRRC, ESAI_PRRC_PDC_MASK, ESAI_PRRC_PDC(ESAI_GPIO)); regmap_update_bits(esai_priv->regmap, REG_ESAI_PCRC, ESAI_PCRC_PC_MASK, ESAI_PCRC_PC(ESAI_GPIO)); return 0; }
static int fsl_esai_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai); bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; u32 width = snd_pcm_format_width(params_format(params)); u32 channels = params_channels(params); u32 bclk, mask, val, ret; bclk = params_rate(params) * esai_priv->slot_width * 2; ret = fsl_esai_set_bclk(dai, tx, bclk); if (ret) return ret; /* Use Normal mode to support monaural audio */ regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), ESAI_xCR_xMOD_MASK, params_channels(params) > 1 ? ESAI_xCR_xMOD_NETWORK : 0); regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), ESAI_xFCR_xFR_MASK, ESAI_xFCR_xFR); mask = ESAI_xFCR_xFR_MASK | ESAI_xFCR_xWA_MASK | ESAI_xFCR_xFWM_MASK | (tx ? ESAI_xFCR_TE_MASK | ESAI_xFCR_TIEN : ESAI_xFCR_RE_MASK); val = ESAI_xFCR_xWA(width) | ESAI_xFCR_xFWM(esai_priv->fifo_depth) | (tx ? ESAI_xFCR_TE(channels) | ESAI_xFCR_TIEN : ESAI_xFCR_RE(channels)); regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), mask, val); mask = ESAI_xCR_xSWS_MASK | (tx ? ESAI_xCR_PADC : 0); val = ESAI_xCR_xSWS(esai_priv->slot_width, width) | (tx ? ESAI_xCR_PADC : 0); regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), mask, val); return 0; }