123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326 |
- From 87f734fa8214b4ddbfdac9b7ac5dc75a3d86badb Mon Sep 17 00:00:00 2001
- From: Shengjiu Wang <[email protected]>
- Date: Tue, 23 Jan 2018 13:26:37 +0800
- Subject: [PATCH] MLK-16224-4: ASoC: fsl_sai: support multi fifo and DSD
- The codec always mux the LRCLK pin to DSD data line, so when
- we want to support DSD, the pinmux is different. For two channel
- DSD, the DSDL is mapped to TX0, but the DSDR is mapped to TX4,
- there is address offset for the fifo address of TX0 and TX4, TX4's
- fifo is not adjacent to TX0's.
- Usually, if mapping is TX0 and TX1, that will be easy for SAI
- and SDMA to handle, that SAI can use the FIFO combine mode, SDMA
- can use the normal script.
- so for DSD:
- 1. The SDMA should use the multi-fifo script, and SAI can't
- use the FIFO combine mode.
- 2. driver should to check the dts configuration(fsl,dataline) for
- which dataline is used corrently
- 3. maxburst is the multiply of datalines
- 4. each channel of DSD occupy one data lane
- 5. according to data lane, set TRCE bits
- Signed-off-by: Shengjiu Wang <[email protected]>
- Reviewed-by: Viorel Suman <[email protected]>
- ---
- sound/soc/fsl/fsl_sai.c | 162 +++++++++++++++++++++++++++++++++++++++++++++---
- sound/soc/fsl/fsl_sai.h | 12 +++-
- 2 files changed, 164 insertions(+), 10 deletions(-)
- --- a/sound/soc/fsl/fsl_sai.c
- +++ b/sound/soc/fsl/fsl_sai.c
- @@ -267,6 +267,7 @@ static int fsl_sai_set_dai_fmt_tr(struct
- if (!sai->is_lsb_first)
- val_cr4 |= FSL_SAI_CR4_MF;
-
- + sai->is_dsp_mode = false;
- /* DAI mode */
- switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
- case SND_SOC_DAIFMT_I2S:
- @@ -305,6 +306,11 @@ static int fsl_sai_set_dai_fmt_tr(struct
- val_cr2 |= FSL_SAI_CR2_BCP;
- sai->is_dsp_mode = true;
- break;
- + case SND_SOC_DAIFMT_PDM:
- + val_cr2 |= FSL_SAI_CR2_BCP;
- + val_cr4 &= ~FSL_SAI_CR4_MF;
- + sai->is_dsp_mode = true;
- + break;
- case SND_SOC_DAIFMT_RIGHT_J:
- /* To be done */
- default:
- @@ -492,12 +498,38 @@ static int fsl_sai_hw_params(struct snd_
- u32 slot_width = word_width;
- u32 pins;
- int ret;
- + int i;
- + int trce_mask = 0;
- + snd_pcm_format_t format = params_format(params);
-
- if (sai->slots)
- slots = sai->slots;
-
- pins = DIV_ROUND_UP(channels, slots);
-
- + if (format == SNDRV_PCM_FORMAT_DSD_U8 ||
- + format == SNDRV_PCM_FORMAT_DSD_U16_LE ||
- + format == SNDRV_PCM_FORMAT_DSD_U16_BE ||
- + format == SNDRV_PCM_FORMAT_DSD_U32_LE ||
- + format == SNDRV_PCM_FORMAT_DSD_U32_BE) {
- + sai->is_dsd = true;
- +
- + if (!IS_ERR_OR_NULL(sai->pins_dsd)) {
- + ret = pinctrl_select_state(sai->pinctrl, sai->pins_dsd);
- + if (ret) {
- + dev_err(cpu_dai->dev,
- + "failed to set proper pins state: %d\n", ret);
- + return ret;
- + }
- + }
- + } else {
- + pinctrl_pm_select_default_state(cpu_dai->dev);
- + sai->is_dsd = false;
- + }
- +
- + if (sai->is_dsd)
- + pins = channels;
- +
- if (sai->slot_width)
- slot_width = sai->slot_width;
-
- @@ -527,7 +559,7 @@ static int fsl_sai_hw_params(struct snd_
- val_cr5 |= FSL_SAI_CR5_WNW(slot_width);
- val_cr5 |= FSL_SAI_CR5_W0W(slot_width);
-
- - if (sai->is_lsb_first)
- + if (sai->is_lsb_first || sai->is_dsd)
- val_cr5 |= FSL_SAI_CR5_FBT(0);
- else
- val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1);
- @@ -560,17 +592,71 @@ static int fsl_sai_hw_params(struct snd_
- }
-
- if (sai->soc->dataline != 0x1) {
- - if (sai->dataline[tx] <= 1)
- +
- + if (sai->dataline[tx] <= 1 || sai->is_multi_lane)
- regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, offset),
- FSL_SAI_CR4_FCOMB_MASK, 0);
- else
- regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, offset),
- FSL_SAI_CR4_FCOMB_MASK, FSL_SAI_CR4_FCOMB_SOFT);
- +
- + if (sai->is_multi_lane) {
- + if (tx) {
- + sai->dma_params_tx.maxburst =
- + FSL_SAI_MAXBURST_TX * pins;
- + if (sai->is_dsd)
- + sai->dma_params_tx.fifo_num = pins +
- + (sai->dataline_off_dsd[tx] << 8);
- + else
- + sai->dma_params_tx.fifo_num = pins +
- + (sai->dataline_off[tx] << 8);
- + } else {
- + sai->dma_params_rx.maxburst =
- + FSL_SAI_MAXBURST_RX * pins;
- + if (sai->is_dsd)
- + sai->dma_params_rx.fifo_num = pins +
- + (sai->dataline_off_dsd[tx] << 8);
- + else
- + sai->dma_params_rx.fifo_num = pins +
- + (sai->dataline_off[tx] << 8);
- + }
- + }
- +
- + snd_soc_dai_init_dma_data(cpu_dai, &sai->dma_params_tx,
- + &sai->dma_params_rx);
- }
-
- - regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, offset),
- + if (sai->is_dsd) {
- + if (__sw_hweight8(sai->dataline_dsd[tx] & 0xFF) < pins) {
- + dev_err(cpu_dai->dev, "channel not supported\n");
- + return -EINVAL;
- + }
- + /*find a proper tcre setting*/
- + for (i = 0; i < 8; i++) {
- + trce_mask = (1 << (i + 1)) - 1;
- + if (__sw_hweight8(sai->dataline_dsd[tx] & trce_mask) == pins)
- + break;
- + }
- +
- + regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, offset),
- FSL_SAI_CR3_TRCE_MASK,
- - FSL_SAI_CR3_TRCE((sai->dataline[tx] & ((1 << pins) - 1))));
- + FSL_SAI_CR3_TRCE((sai->dataline_dsd[tx] & trce_mask)));
- + } else {
- + if (__sw_hweight8(sai->dataline[tx] & 0xFF) < pins) {
- + dev_err(cpu_dai->dev, "channel not supported\n");
- + return -EINVAL;
- + }
- + /*find a proper tcre setting*/
- + for (i = 0; i < 8; i++) {
- + trce_mask = (1 << (i + 1)) - 1;
- + if (__sw_hweight8(sai->dataline[tx] & trce_mask) == pins)
- + break;
- + }
- +
- + regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, offset),
- + FSL_SAI_CR3_TRCE_MASK,
- + FSL_SAI_CR3_TRCE((sai->dataline[tx] & trce_mask)));
- + }
-
- regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, offset),
- FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
- @@ -610,9 +696,18 @@ static int fsl_sai_trigger(struct snd_pc
- unsigned char offset = sai->soc->reg_offset;
- bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
- u8 channels = substream->runtime->channels;
- + u32 slots = (channels == 1) ? 2 : channels;
- u32 xcsr, count = 100;
- - int i;
- + u32 pins;
- + int i = 0, j = 0, k = 0;
- +
- + if (sai->slots)
- + slots = sai->slots;
- +
- + pins = DIV_ROUND_UP(channels, slots);
-
- + if (sai->is_dsd)
- + pins = channels;
- /*
- * Asynchronous mode: Clear SYNC for both Tx and Rx.
- * Rx sync with Tx clocks: Clear SYNC for Tx, set it for Rx.
- @@ -631,10 +726,19 @@ static int fsl_sai_trigger(struct snd_pc
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_RESUME:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- - for (i = 0; tx && i < channels; i++)
- - regmap_write(sai->regmap, FSL_SAI_TDR0, 0x0);
- - if (tx)
- - udelay(10);
- +
- + for (i = 0; tx && i < channels; i++) {
- + while (tx && i < channels)
- + if (sai->dataline[tx] & (1 << j)) {
- + regmap_write(sai->regmap, FSL_SAI_TDR0 + j * 0x4, 0x0);
- + i++;
- + k++;
- + }
- + j++;
- +
- + if (k%pins == 0)
- + j = 0;
- + }
-
- regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, offset),
- FSL_SAI_CSR_FRDE, FSL_SAI_CSR_FRDE);
- @@ -994,6 +1098,7 @@ static int fsl_sai_probe(struct platform
- char tmp[8];
- int irq, ret, i;
- int index;
- + int firstbitidx, nextbitidx;
- struct regmap_config fsl_sai_regmap_config = fsl_sai_v2_regmap_config;
- unsigned long irqflags = 0;
-
- @@ -1048,6 +1153,9 @@ static int fsl_sai_probe(struct platform
- }
- }
-
- + if (of_find_property(np, "fsl,sai-multi-lane", NULL))
- + sai->is_multi_lane = true;
- +
- /*dataline mask for rx and tx*/
- ret = of_property_read_u32_index(np, "fsl,dataline", 0, &sai->dataline[0]);
- if (ret)
- @@ -1062,6 +1170,37 @@ static int fsl_sai_probe(struct platform
- return -EINVAL;
- }
-
- + for (i = 0; i < 2; i++) {
- + firstbitidx = find_first_bit((const unsigned long *)&sai->dataline[i], 8);
- + nextbitidx = find_next_bit((const unsigned long *)&sai->dataline[i], 8, firstbitidx+1);
- + sai->dataline_off[i] = nextbitidx - firstbitidx - 1;
- +
- + if (sai->dataline_off[i] < 0 || sai->dataline_off[i] >= 7)
- + sai->dataline_off[i] = 0;
- + }
- +
- + ret = of_property_read_u32_index(np, "fsl,dataline,dsd", 0, &sai->dataline_dsd[0]);
- + if (ret)
- + sai->dataline_dsd[0] = 1;
- +
- + ret = of_property_read_u32_index(np, "fsl,dataline,dsd", 1, &sai->dataline_dsd[1]);
- + if (ret)
- + sai->dataline_dsd[1] = 1;
- +
- + if ((sai->dataline_dsd[0] & (~sai->soc->dataline)) || sai->dataline_dsd[1] & (~sai->soc->dataline)) {
- + dev_err(&pdev->dev, "dataline setting error, Mask is 0x%x\n", sai->soc->dataline);
- + return -EINVAL;
- + }
- +
- + for (i = 0; i < 2; i++) {
- + firstbitidx = find_first_bit((const unsigned long *)&sai->dataline_dsd[i], 8);
- + nextbitidx = find_next_bit((const unsigned long *)&sai->dataline_dsd[i], 8, firstbitidx+1);
- + sai->dataline_off_dsd[i] = nextbitidx - firstbitidx - 1;
- +
- + if (sai->dataline_off_dsd[i] < 0 || sai->dataline_off_dsd[i] >= 7)
- + sai->dataline_off_dsd[i] = 0;
- + }
- +
- if ((of_find_property(np, "fsl,i2s-xtor", NULL) != NULL) ||
- (of_find_property(np, "fsl,txm-rxs", NULL) != NULL))
- {
- @@ -1144,6 +1283,11 @@ static int fsl_sai_probe(struct platform
- sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX;
- sai->dma_params_tx.maxburst = FSL_SAI_MAXBURST_TX;
-
- + sai->pinctrl = devm_pinctrl_get(&pdev->dev);
- +
- + if (!IS_ERR_OR_NULL(sai->pinctrl))
- + sai->pins_dsd = pinctrl_lookup_state(sai->pinctrl, "dsd");
- +
- platform_set_drvdata(pdev, sai);
-
- pm_runtime_enable(&pdev->dev);
- --- a/sound/soc/fsl/fsl_sai.h
- +++ b/sound/soc/fsl/fsl_sai.h
- @@ -11,7 +11,10 @@
-
- #define FSL_SAI_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
- SNDRV_PCM_FMTBIT_S24_LE |\
- - SNDRV_PCM_FMTBIT_S32_LE)
- + SNDRV_PCM_FMTBIT_S32_LE |\
- + SNDRV_PCM_FMTBIT_DSD_U8 |\
- + SNDRV_PCM_FMTBIT_DSD_U16_LE |\
- + SNDRV_PCM_FMTBIT_DSD_U32_LE)
-
- /* SAI Register Map Register */
- #define FSL_SAI_TCSR(offset) (0x00 + offset) /* SAI Transmit Control */
- @@ -172,9 +175,14 @@ struct fsl_sai {
- bool slave_mode[2];
- bool is_lsb_first;
- bool is_dsp_mode;
- + bool is_multi_lane;
- bool synchronous[2];
- bool is_stream_opened[2];
- + bool is_dsd;
- unsigned int dataline[2];
- + unsigned int dataline_dsd[2];
- + unsigned int dataline_off[2];
- + unsigned int dataline_off_dsd[2];
- unsigned int masterflag[2];
-
- unsigned int mclk_id[2];
- @@ -188,6 +196,8 @@ struct fsl_sai {
- struct snd_dmaengine_dai_dma_data dma_params_tx;
- const struct fsl_sai_soc_data *soc;
- struct pm_qos_request pm_qos_req;
- + struct pinctrl *pinctrl;
- + struct pinctrl_state *pins_dsd;
- };
-
- #define TX 1
|