sound:starfive:spdif:Add single-channel
authorXingyu Wu <xingyu.wu@starfivetech.com>
Thu, 28 Jul 2022 06:03:20 +0000 (14:03 +0800)
committerXingyu Wu <xingyu.wu@starfivetech.com>
Thu, 28 Jul 2022 06:03:25 +0000 (14:03 +0800)
Spdif supports single-channel audio playback.

Signed-off-by: Xingyu Wu <xingyu.wu@starfivetech.com>
sound/soc/starfive/starfive_spdif.c
sound/soc/starfive/starfive_spdif.h
sound/soc/starfive/starfive_spdif_pcm.c

index 177c361..34bc721 100755 (executable)
@@ -145,7 +145,17 @@ static int sf_spdif_hw_params(struct snd_pcm_substream *substream,
        format = params_format(params);
 
        switch (channels) {
+       case 1:
+               regmap_update_bits(spdif->regmap, SPDIF_CTRL,
+                       SPDIF_CHANNEL_MODE, SPDIF_CHANNEL_MODE);
+               regmap_update_bits(spdif->regmap, SPDIF_CTRL,
+                       SPDIF_DUPLICATE, SPDIF_DUPLICATE);
+               spdif->channels = false;
+               break;
        case 2:
+               regmap_update_bits(spdif->regmap, SPDIF_CTRL,
+                       SPDIF_CHANNEL_MODE, 0);
+               spdif->channels = true;
                break;
        default:
                dev_err(dai->dev, "invalid channels number\n");
@@ -186,8 +196,9 @@ static int sf_spdif_hw_params(struct snd_pcm_substream *substream,
                return ret;
        }
 
+       mclk = clk_get_rate(spdif->mclk_inner);
        /* (FCLK)4096000/128=32000 */
-       tsamplerate = (32000 + rate/2)/rate - 1;
+       tsamplerate = (mclk / 128 + rate / 2) / rate - 1;
 
        if (tsamplerate < 3)
                tsamplerate = 3;
@@ -225,6 +236,7 @@ static int sf_spdif_resets_get(struct platform_device *pdev,
                        { .id = "rst_apb" },
        };
        int ret = devm_reset_control_bulk_get_exclusive(&pdev->dev, ARRAY_SIZE(resets), resets);
+
        if (ret)
                return ret;
 
@@ -377,7 +389,7 @@ static struct snd_soc_dai_driver sf_spdif_dai = {
        .probe = sf_spdif_dai_probe,
        .playback = {
                .stream_name = "Playback",
-               .channels_min = 2,
+               .channels_min = 1,
                .channels_max = 2,
                .rates = SF_PCM_RATE_8000_22050,
                .formats = SNDRV_PCM_FMTBIT_S16_LE | \
index 805e93e..12f76f7 100755 (executable)
@@ -146,6 +146,7 @@ struct sf_spdif_dev {
                        bool *period_elapsed, snd_pcm_format_t format);
 
        snd_pcm_format_t format;
+       bool channels;
        unsigned int tx_ptr;
        unsigned int rx_ptr;
        struct clk* spdif_apb;
index ba5cd04..d249e8d 100755 (executable)
@@ -32,35 +32,66 @@ static unsigned int sf_spdif_pcm_tx(struct sf_spdif_dev *dev,
                struct snd_pcm_runtime *runtime, unsigned int tx_ptr, 
                bool *period_elapsed, snd_pcm_format_t format) 
 { 
-       const u16 (*p16)[2] = (void *)runtime->dma_area; 
-       const u32 (*p32)[2] = (void *)runtime->dma_area; 
        u32 data[2];
        unsigned int period_pos = tx_ptr % runtime->period_size; 
        int i;  
 
-       for (i = 0; i < dev->fifo_th; i++) { 
-               if (SNDRV_PCM_FORMAT_S16_LE == format) {
-                       data[0] = p16[tx_ptr][0];
-                       data[1] = p16[tx_ptr][1];
-                       data[0] = data[0]<<8;
-                       data[1] = data[1]<<8;
-               } else if (SNDRV_PCM_FORMAT_S24_LE == format) {
-                       data[0] = p32[tx_ptr][0];
-                       data[1] = p32[tx_ptr][1];
-               } else if (SNDRV_PCM_FORMAT_S32_LE == format) {
-                       data[0] = p32[tx_ptr][0];
-                       data[1] = p32[tx_ptr][1];
-                       data[0] = data[0]>>8;
-                       data[1] = data[1]>>8;
+       /* two- channel and signal-channel mode */
+       if (dev->channels) {
+               const u16 (*p16)[2] = (void *)runtime->dma_area;
+               const u32 (*p32)[2] = (void *)runtime->dma_area;
+
+               for (i = 0; i < dev->fifo_th; i++) {
+                       if (SNDRV_PCM_FORMAT_S16_LE == format) {
+                               data[0] = p16[tx_ptr][0];
+                               data[0] = data[0]<<8;
+                               data[0] &= 0x00ffff00;
+                               data[1] = p16[tx_ptr][1];
+                               data[1] = data[1]<<8;
+                               data[1] &= 0x00ffff00;
+                       } else if (SNDRV_PCM_FORMAT_S24_LE == format) {
+                               data[0] = p32[tx_ptr][0];
+                               data[0] &= 0x00ffffff;
+                               data[1] = p32[tx_ptr][1];
+                               data[1] &= 0x00ffffff;
+                       } else if (SNDRV_PCM_FORMAT_S32_LE == format) {
+                               data[0] = p32[tx_ptr][0];
+                               data[0] = data[0]>>8;
+                               data[1] = p32[tx_ptr][1];
+                               data[1] = data[1]>>8;
+                       }
+
+                       iowrite32(data[0], dev->spdif_base + SPDIF_FIFO_ADDR);
+                       iowrite32(data[1], dev->spdif_base + SPDIF_FIFO_ADDR);
+                       period_pos++;
+                       if (++tx_ptr >= runtime->buffer_size) {
+                               tx_ptr = 0;
+                       }
                }
-               
-               iowrite32(data[0], dev->spdif_base + SPDIF_FIFO_ADDR); 
-               iowrite32(data[1], dev->spdif_base + SPDIF_FIFO_ADDR); 
-               period_pos++; 
-               if (++tx_ptr >= runtime->buffer_size) {
-                       tx_ptr = 0; 
+       } else {
+               const u16 (*p16) = (void *)runtime->dma_area;
+               const u32 (*p32) = (void *)runtime->dma_area;
+
+               for (i = 0; i < dev->fifo_th; i++) {
+                       if (SNDRV_PCM_FORMAT_S16_LE == format) {
+                               data[0] = p16[tx_ptr];
+                               data[0] = data[0]<<8;
+                               data[0] &= 0x00ffff00;
+                       } else if (SNDRV_PCM_FORMAT_S24_LE == format) {
+                               data[0] = p32[tx_ptr];
+                               data[0] &= 0x00ffffff;
+                       } else if (SNDRV_PCM_FORMAT_S32_LE == format) {
+                               data[0] = p32[tx_ptr];
+                               data[0] = data[0]>>8;
+                       }
+
+                       iowrite32(data[0], dev->spdif_base + SPDIF_FIFO_ADDR);
+                       period_pos++;
+                       if (++tx_ptr >= runtime->buffer_size) {
+                               tx_ptr = 0;
+                       }
                }
-       } 
+       }
 
        *period_elapsed = period_pos >= runtime->period_size; 
        return tx_ptr; 
@@ -116,7 +147,7 @@ static const struct snd_pcm_hardware sf_pcm_hardware = {
        .formats = SNDRV_PCM_FMTBIT_S16_LE |
                SNDRV_PCM_FMTBIT_S24_LE |
                SNDRV_PCM_FMTBIT_S32_LE,
-       .channels_min = 2,
+       .channels_min = 1,
        .channels_max = 2,
        .buffer_bytes_max = BUFFER_BYTES_MAX,
        .period_bytes_min = PERIOD_BYTES_MIN,
@@ -198,6 +229,7 @@ static int sf_pcm_hw_params(struct snd_soc_component *component,
        struct sf_spdif_dev *dev = runtime->private_data;
 
        switch (params_channels(hw_params)) {
+       case 1:
        case 2:
                break;
        default: