0001
0002
0003
0004
0005
0006 #include <linux/clk.h>
0007 #include <sound/pcm_params.h>
0008 #include <sound/soc.h>
0009 #include <sound/soc-dai.h>
0010
0011 #include "aiu.h"
0012 #include "aiu-fifo.h"
0013
0014 #define AIU_IEC958_DCU_FF_CTRL_EN BIT(0)
0015 #define AIU_IEC958_DCU_FF_CTRL_AUTO_DISABLE BIT(1)
0016 #define AIU_IEC958_DCU_FF_CTRL_IRQ_MODE GENMASK(3, 2)
0017 #define AIU_IEC958_DCU_FF_CTRL_IRQ_OUT_THD BIT(2)
0018 #define AIU_IEC958_DCU_FF_CTRL_IRQ_FRAME_READ BIT(3)
0019 #define AIU_IEC958_DCU_FF_CTRL_SYNC_HEAD_EN BIT(4)
0020 #define AIU_IEC958_DCU_FF_CTRL_BYTE_SEEK BIT(5)
0021 #define AIU_IEC958_DCU_FF_CTRL_CONTINUE BIT(6)
0022 #define AIU_MEM_IEC958_CONTROL_ENDIAN GENMASK(5, 3)
0023 #define AIU_MEM_IEC958_CONTROL_RD_DDR BIT(6)
0024 #define AIU_MEM_IEC958_CONTROL_MODE_16BIT BIT(7)
0025 #define AIU_MEM_IEC958_CONTROL_MODE_LINEAR BIT(8)
0026 #define AIU_MEM_IEC958_BUF_CNTL_INIT BIT(0)
0027
0028 #define AIU_FIFO_SPDIF_BLOCK 8
0029
0030 static struct snd_pcm_hardware fifo_spdif_pcm = {
0031 .info = (SNDRV_PCM_INFO_INTERLEAVED |
0032 SNDRV_PCM_INFO_MMAP |
0033 SNDRV_PCM_INFO_MMAP_VALID |
0034 SNDRV_PCM_INFO_PAUSE),
0035 .formats = AIU_FORMATS,
0036 .rate_min = 5512,
0037 .rate_max = 192000,
0038 .channels_min = 2,
0039 .channels_max = 2,
0040 .period_bytes_min = AIU_FIFO_SPDIF_BLOCK,
0041 .period_bytes_max = AIU_FIFO_SPDIF_BLOCK * USHRT_MAX,
0042 .periods_min = 2,
0043 .periods_max = UINT_MAX,
0044
0045
0046 .buffer_bytes_max = 1 * 1024 * 1024,
0047 };
0048
0049 static void fifo_spdif_dcu_enable(struct snd_soc_component *component,
0050 bool enable)
0051 {
0052 snd_soc_component_update_bits(component, AIU_IEC958_DCU_FF_CTRL,
0053 AIU_IEC958_DCU_FF_CTRL_EN,
0054 enable ? AIU_IEC958_DCU_FF_CTRL_EN : 0);
0055 }
0056
0057 static int fifo_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
0058 struct snd_soc_dai *dai)
0059 {
0060 struct snd_soc_component *component = dai->component;
0061 int ret;
0062
0063 ret = aiu_fifo_trigger(substream, cmd, dai);
0064 if (ret)
0065 return ret;
0066
0067 switch (cmd) {
0068 case SNDRV_PCM_TRIGGER_START:
0069 case SNDRV_PCM_TRIGGER_RESUME:
0070 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
0071 fifo_spdif_dcu_enable(component, true);
0072 break;
0073 case SNDRV_PCM_TRIGGER_SUSPEND:
0074 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
0075 case SNDRV_PCM_TRIGGER_STOP:
0076 fifo_spdif_dcu_enable(component, false);
0077 break;
0078 default:
0079 return -EINVAL;
0080 }
0081
0082 return 0;
0083 }
0084
0085 static int fifo_spdif_prepare(struct snd_pcm_substream *substream,
0086 struct snd_soc_dai *dai)
0087 {
0088 struct snd_soc_component *component = dai->component;
0089 int ret;
0090
0091 ret = aiu_fifo_prepare(substream, dai);
0092 if (ret)
0093 return ret;
0094
0095 snd_soc_component_update_bits(component,
0096 AIU_MEM_IEC958_BUF_CNTL,
0097 AIU_MEM_IEC958_BUF_CNTL_INIT,
0098 AIU_MEM_IEC958_BUF_CNTL_INIT);
0099 snd_soc_component_update_bits(component,
0100 AIU_MEM_IEC958_BUF_CNTL,
0101 AIU_MEM_IEC958_BUF_CNTL_INIT, 0);
0102
0103 return 0;
0104 }
0105
0106 static int fifo_spdif_hw_params(struct snd_pcm_substream *substream,
0107 struct snd_pcm_hw_params *params,
0108 struct snd_soc_dai *dai)
0109 {
0110 struct snd_soc_component *component = dai->component;
0111 unsigned int val;
0112 int ret;
0113
0114 ret = aiu_fifo_hw_params(substream, params, dai);
0115 if (ret)
0116 return ret;
0117
0118 val = AIU_MEM_IEC958_CONTROL_RD_DDR |
0119 AIU_MEM_IEC958_CONTROL_MODE_LINEAR;
0120
0121 switch (params_physical_width(params)) {
0122 case 16:
0123 val |= AIU_MEM_IEC958_CONTROL_MODE_16BIT;
0124 break;
0125 case 32:
0126 break;
0127 default:
0128 dev_err(dai->dev, "Unsupported physical width %u\n",
0129 params_physical_width(params));
0130 return -EINVAL;
0131 }
0132
0133 snd_soc_component_update_bits(component, AIU_MEM_IEC958_CONTROL,
0134 AIU_MEM_IEC958_CONTROL_ENDIAN |
0135 AIU_MEM_IEC958_CONTROL_RD_DDR |
0136 AIU_MEM_IEC958_CONTROL_MODE_LINEAR |
0137 AIU_MEM_IEC958_CONTROL_MODE_16BIT,
0138 val);
0139
0140
0141 snd_soc_component_write(component, AIU_IEC958_BPF,
0142 params_period_bytes(params));
0143
0144
0145
0146
0147
0148 snd_soc_component_update_bits(component, AIU_IEC958_DCU_FF_CTRL,
0149 AIU_IEC958_DCU_FF_CTRL_AUTO_DISABLE |
0150 AIU_IEC958_DCU_FF_CTRL_IRQ_MODE |
0151 AIU_IEC958_DCU_FF_CTRL_SYNC_HEAD_EN,
0152 AIU_IEC958_DCU_FF_CTRL_IRQ_FRAME_READ);
0153
0154 return 0;
0155 }
0156
0157 const struct snd_soc_dai_ops aiu_fifo_spdif_dai_ops = {
0158 .trigger = fifo_spdif_trigger,
0159 .prepare = fifo_spdif_prepare,
0160 .hw_params = fifo_spdif_hw_params,
0161 .startup = aiu_fifo_startup,
0162 .shutdown = aiu_fifo_shutdown,
0163 };
0164
0165 int aiu_fifo_spdif_dai_probe(struct snd_soc_dai *dai)
0166 {
0167 struct snd_soc_component *component = dai->component;
0168 struct aiu *aiu = snd_soc_component_get_drvdata(component);
0169 struct aiu_fifo *fifo;
0170 int ret;
0171
0172 ret = aiu_fifo_dai_probe(dai);
0173 if (ret)
0174 return ret;
0175
0176 fifo = dai->playback_dma_data;
0177
0178 fifo->pcm = &fifo_spdif_pcm;
0179 fifo->mem_offset = AIU_MEM_IEC958_START;
0180 fifo->fifo_block = 1;
0181 fifo->pclk = aiu->spdif.clks[PCLK].clk;
0182 fifo->irq = aiu->spdif.irq;
0183
0184 return 0;
0185 }