1 // SPDX-License-Identifier: GPL-2.0
3 // Copyright (c) 2020 BayLibre, SAS.
4 // Author: Jerome Brunet <jbrunet@baylibre.com>
7 #include <sound/pcm_params.h>
9 #include <sound/soc-dai.h>
14 #define AIU_IEC958_DCU_FF_CTRL_EN BIT(0)
15 #define AIU_IEC958_DCU_FF_CTRL_AUTO_DISABLE BIT(1)
16 #define AIU_IEC958_DCU_FF_CTRL_IRQ_MODE GENMASK(3, 2)
17 #define AIU_IEC958_DCU_FF_CTRL_IRQ_OUT_THD BIT(2)
18 #define AIU_IEC958_DCU_FF_CTRL_IRQ_FRAME_READ BIT(3)
19 #define AIU_IEC958_DCU_FF_CTRL_SYNC_HEAD_EN BIT(4)
20 #define AIU_IEC958_DCU_FF_CTRL_BYTE_SEEK BIT(5)
21 #define AIU_IEC958_DCU_FF_CTRL_CONTINUE BIT(6)
22 #define AIU_MEM_IEC958_CONTROL_ENDIAN GENMASK(5, 3)
23 #define AIU_MEM_IEC958_CONTROL_RD_DDR BIT(6)
24 #define AIU_MEM_IEC958_CONTROL_MODE_16BIT BIT(7)
25 #define AIU_MEM_IEC958_CONTROL_MODE_LINEAR BIT(8)
26 #define AIU_MEM_IEC958_BUF_CNTL_INIT BIT(0)
28 #define AIU_FIFO_SPDIF_BLOCK 8
30 static struct snd_pcm_hardware fifo_spdif_pcm
= {
31 .info
= (SNDRV_PCM_INFO_INTERLEAVED
|
33 SNDRV_PCM_INFO_MMAP_VALID
|
34 SNDRV_PCM_INFO_PAUSE
),
35 .formats
= AIU_FORMATS
,
40 .period_bytes_min
= AIU_FIFO_SPDIF_BLOCK
,
41 .period_bytes_max
= AIU_FIFO_SPDIF_BLOCK
* USHRT_MAX
,
43 .periods_max
= UINT_MAX
,
45 /* No real justification for this */
46 .buffer_bytes_max
= 1 * 1024 * 1024,
49 static void fifo_spdif_dcu_enable(struct snd_soc_component
*component
,
52 snd_soc_component_update_bits(component
, AIU_IEC958_DCU_FF_CTRL
,
53 AIU_IEC958_DCU_FF_CTRL_EN
,
54 enable
? AIU_IEC958_DCU_FF_CTRL_EN
: 0);
57 static int fifo_spdif_trigger(struct snd_pcm_substream
*substream
, int cmd
,
58 struct snd_soc_dai
*dai
)
60 struct snd_soc_component
*component
= dai
->component
;
63 ret
= aiu_fifo_trigger(substream
, cmd
, dai
);
68 case SNDRV_PCM_TRIGGER_START
:
69 case SNDRV_PCM_TRIGGER_RESUME
:
70 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
71 fifo_spdif_dcu_enable(component
, true);
73 case SNDRV_PCM_TRIGGER_SUSPEND
:
74 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
75 case SNDRV_PCM_TRIGGER_STOP
:
76 fifo_spdif_dcu_enable(component
, false);
85 static int fifo_spdif_prepare(struct snd_pcm_substream
*substream
,
86 struct snd_soc_dai
*dai
)
88 struct snd_soc_component
*component
= dai
->component
;
91 ret
= aiu_fifo_prepare(substream
, dai
);
95 snd_soc_component_update_bits(component
,
96 AIU_MEM_IEC958_BUF_CNTL
,
97 AIU_MEM_IEC958_BUF_CNTL_INIT
,
98 AIU_MEM_IEC958_BUF_CNTL_INIT
);
99 snd_soc_component_update_bits(component
,
100 AIU_MEM_IEC958_BUF_CNTL
,
101 AIU_MEM_IEC958_BUF_CNTL_INIT
, 0);
106 static int fifo_spdif_hw_params(struct snd_pcm_substream
*substream
,
107 struct snd_pcm_hw_params
*params
,
108 struct snd_soc_dai
*dai
)
110 struct snd_soc_component
*component
= dai
->component
;
114 ret
= aiu_fifo_hw_params(substream
, params
, dai
);
118 val
= AIU_MEM_IEC958_CONTROL_RD_DDR
|
119 AIU_MEM_IEC958_CONTROL_MODE_LINEAR
;
121 switch (params_physical_width(params
)) {
123 val
|= AIU_MEM_IEC958_CONTROL_MODE_16BIT
;
128 dev_err(dai
->dev
, "Unsupported physical width %u\n",
129 params_physical_width(params
));
133 snd_soc_component_update_bits(component
, AIU_MEM_IEC958_CONTROL
,
134 AIU_MEM_IEC958_CONTROL_ENDIAN
|
135 AIU_MEM_IEC958_CONTROL_RD_DDR
|
136 AIU_MEM_IEC958_CONTROL_MODE_LINEAR
|
137 AIU_MEM_IEC958_CONTROL_MODE_16BIT
,
140 /* Number bytes read by the FIFO between each IRQ */
141 snd_soc_component_write(component
, AIU_IEC958_BPF
,
142 params_period_bytes(params
));
145 * AUTO_DISABLE and SYNC_HEAD are enabled by default but
146 * this should be disabled in PCM (uncompressed) mode
148 snd_soc_component_update_bits(component
, AIU_IEC958_DCU_FF_CTRL
,
149 AIU_IEC958_DCU_FF_CTRL_AUTO_DISABLE
|
150 AIU_IEC958_DCU_FF_CTRL_IRQ_MODE
|
151 AIU_IEC958_DCU_FF_CTRL_SYNC_HEAD_EN
,
152 AIU_IEC958_DCU_FF_CTRL_IRQ_FRAME_READ
);
157 const struct snd_soc_dai_ops aiu_fifo_spdif_dai_ops
= {
158 .trigger
= fifo_spdif_trigger
,
159 .prepare
= fifo_spdif_prepare
,
160 .hw_params
= fifo_spdif_hw_params
,
161 .hw_free
= aiu_fifo_hw_free
,
162 .startup
= aiu_fifo_startup
,
163 .shutdown
= aiu_fifo_shutdown
,
166 int aiu_fifo_spdif_dai_probe(struct snd_soc_dai
*dai
)
168 struct snd_soc_component
*component
= dai
->component
;
169 struct aiu
*aiu
= snd_soc_component_get_drvdata(component
);
170 struct aiu_fifo
*fifo
;
173 ret
= aiu_fifo_dai_probe(dai
);
177 fifo
= dai
->playback_dma_data
;
179 fifo
->pcm
= &fifo_spdif_pcm
;
180 fifo
->mem_offset
= AIU_MEM_IEC958_START
;
181 fifo
->fifo_block
= 1;
182 fifo
->pclk
= aiu
->spdif
.clks
[PCLK
].clk
;
183 fifo
->irq
= aiu
->spdif
.irq
;