0001
0002
0003
0004
0005
0006 #include <linux/bitfield.h>
0007 #include <linux/clk.h>
0008 #include <sound/pcm_params.h>
0009 #include <sound/soc.h>
0010 #include <sound/soc-dai.h>
0011
0012 #include "aiu.h"
0013 #include "aiu-fifo.h"
0014
0015 #define AIU_I2S_SOURCE_DESC_MODE_8CH BIT(0)
0016 #define AIU_I2S_SOURCE_DESC_MODE_24BIT BIT(5)
0017 #define AIU_I2S_SOURCE_DESC_MODE_32BIT BIT(9)
0018 #define AIU_I2S_SOURCE_DESC_MODE_SPLIT BIT(11)
0019 #define AIU_MEM_I2S_MASKS_IRQ_BLOCK GENMASK(31, 16)
0020 #define AIU_MEM_I2S_CONTROL_MODE_16BIT BIT(6)
0021 #define AIU_MEM_I2S_BUF_CNTL_INIT BIT(0)
0022 #define AIU_RST_SOFT_I2S_FAST BIT(0)
0023 #define AIU_I2S_MISC_HOLD_EN BIT(2)
0024 #define AIU_I2S_MISC_FORCE_LEFT_RIGHT BIT(4)
0025
0026 #define AIU_FIFO_I2S_BLOCK 256
0027
0028 static struct snd_pcm_hardware fifo_i2s_pcm = {
0029 .info = (SNDRV_PCM_INFO_INTERLEAVED |
0030 SNDRV_PCM_INFO_MMAP |
0031 SNDRV_PCM_INFO_MMAP_VALID |
0032 SNDRV_PCM_INFO_PAUSE),
0033 .formats = AIU_FORMATS,
0034 .rate_min = 5512,
0035 .rate_max = 192000,
0036 .channels_min = 2,
0037 .channels_max = 8,
0038 .period_bytes_min = AIU_FIFO_I2S_BLOCK,
0039 .period_bytes_max = AIU_FIFO_I2S_BLOCK * USHRT_MAX,
0040 .periods_min = 2,
0041 .periods_max = UINT_MAX,
0042
0043
0044 .buffer_bytes_max = 1 * 1024 * 1024,
0045 };
0046
0047 static int aiu_fifo_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
0048 struct snd_soc_dai *dai)
0049 {
0050 struct snd_soc_component *component = dai->component;
0051
0052 switch (cmd) {
0053 case SNDRV_PCM_TRIGGER_START:
0054 case SNDRV_PCM_TRIGGER_RESUME:
0055 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
0056 snd_soc_component_write(component, AIU_RST_SOFT,
0057 AIU_RST_SOFT_I2S_FAST);
0058 snd_soc_component_read(component, AIU_I2S_SYNC);
0059 break;
0060 }
0061
0062 return aiu_fifo_trigger(substream, cmd, dai);
0063 }
0064
0065 static int aiu_fifo_i2s_prepare(struct snd_pcm_substream *substream,
0066 struct snd_soc_dai *dai)
0067 {
0068 struct snd_soc_component *component = dai->component;
0069 int ret;
0070
0071 ret = aiu_fifo_prepare(substream, dai);
0072 if (ret)
0073 return ret;
0074
0075 snd_soc_component_update_bits(component,
0076 AIU_MEM_I2S_BUF_CNTL,
0077 AIU_MEM_I2S_BUF_CNTL_INIT,
0078 AIU_MEM_I2S_BUF_CNTL_INIT);
0079 snd_soc_component_update_bits(component,
0080 AIU_MEM_I2S_BUF_CNTL,
0081 AIU_MEM_I2S_BUF_CNTL_INIT, 0);
0082
0083 return 0;
0084 }
0085
0086 static int aiu_fifo_i2s_hw_params(struct snd_pcm_substream *substream,
0087 struct snd_pcm_hw_params *params,
0088 struct snd_soc_dai *dai)
0089 {
0090 struct snd_soc_component *component = dai->component;
0091 struct aiu_fifo *fifo = dai->playback_dma_data;
0092 unsigned int val;
0093 int ret;
0094
0095 snd_soc_component_update_bits(component, AIU_I2S_MISC,
0096 AIU_I2S_MISC_HOLD_EN,
0097 AIU_I2S_MISC_HOLD_EN);
0098
0099 ret = aiu_fifo_hw_params(substream, params, dai);
0100 if (ret)
0101 return ret;
0102
0103 switch (params_physical_width(params)) {
0104 case 16:
0105 val = AIU_MEM_I2S_CONTROL_MODE_16BIT;
0106 break;
0107 case 32:
0108 val = 0;
0109 break;
0110 default:
0111 dev_err(dai->dev, "Unsupported physical width %u\n",
0112 params_physical_width(params));
0113 return -EINVAL;
0114 }
0115
0116 snd_soc_component_update_bits(component, AIU_MEM_I2S_CONTROL,
0117 AIU_MEM_I2S_CONTROL_MODE_16BIT,
0118 val);
0119
0120
0121 val = params_period_bytes(params) / fifo->fifo_block;
0122 val = FIELD_PREP(AIU_MEM_I2S_MASKS_IRQ_BLOCK, val);
0123 snd_soc_component_update_bits(component, AIU_MEM_I2S_MASKS,
0124 AIU_MEM_I2S_MASKS_IRQ_BLOCK, val);
0125
0126
0127
0128
0129
0130
0131
0132 snd_soc_component_update_bits(component, AIU_I2S_MISC,
0133 AIU_I2S_MISC_FORCE_LEFT_RIGHT,
0134 AIU_I2S_MISC_FORCE_LEFT_RIGHT);
0135
0136 snd_soc_component_update_bits(component, AIU_I2S_MISC,
0137 AIU_I2S_MISC_HOLD_EN, 0);
0138
0139 return 0;
0140 }
0141
0142 const struct snd_soc_dai_ops aiu_fifo_i2s_dai_ops = {
0143 .trigger = aiu_fifo_i2s_trigger,
0144 .prepare = aiu_fifo_i2s_prepare,
0145 .hw_params = aiu_fifo_i2s_hw_params,
0146 .startup = aiu_fifo_startup,
0147 .shutdown = aiu_fifo_shutdown,
0148 };
0149
0150 int aiu_fifo_i2s_dai_probe(struct snd_soc_dai *dai)
0151 {
0152 struct snd_soc_component *component = dai->component;
0153 struct aiu *aiu = snd_soc_component_get_drvdata(component);
0154 struct aiu_fifo *fifo;
0155 int ret;
0156
0157 ret = aiu_fifo_dai_probe(dai);
0158 if (ret)
0159 return ret;
0160
0161 fifo = dai->playback_dma_data;
0162
0163 fifo->pcm = &fifo_i2s_pcm;
0164 fifo->mem_offset = AIU_MEM_I2S_START;
0165 fifo->fifo_block = AIU_FIFO_I2S_BLOCK;
0166 fifo->pclk = aiu->i2s.clks[PCLK].clk;
0167 fifo->irq = aiu->i2s.irq;
0168
0169 return 0;
0170 }