Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/soc/meson/aiu-fifo-spdif.c
26436 views
1
// SPDX-License-Identifier: GPL-2.0
2
//
3
// Copyright (c) 2020 BayLibre, SAS.
4
// Author: Jerome Brunet <[email protected]>
5
6
#include <linux/clk.h>
7
#include <sound/pcm_params.h>
8
#include <sound/soc.h>
9
#include <sound/soc-dai.h>
10
11
#include "aiu.h"
12
#include "aiu-fifo.h"
13
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)
27
28
#define AIU_FIFO_SPDIF_BLOCK 8
29
30
static const struct snd_pcm_hardware fifo_spdif_pcm = {
31
.info = (SNDRV_PCM_INFO_INTERLEAVED |
32
SNDRV_PCM_INFO_MMAP |
33
SNDRV_PCM_INFO_MMAP_VALID |
34
SNDRV_PCM_INFO_PAUSE),
35
.formats = AIU_FORMATS,
36
.rate_min = 5512,
37
.rate_max = 192000,
38
.channels_min = 2,
39
.channels_max = 2,
40
.period_bytes_min = AIU_FIFO_SPDIF_BLOCK,
41
.period_bytes_max = AIU_FIFO_SPDIF_BLOCK * USHRT_MAX,
42
.periods_min = 2,
43
.periods_max = UINT_MAX,
44
45
/* No real justification for this */
46
.buffer_bytes_max = 1 * 1024 * 1024,
47
};
48
49
static void fifo_spdif_dcu_enable(struct snd_soc_component *component,
50
bool enable)
51
{
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);
55
}
56
57
static int fifo_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
58
struct snd_soc_dai *dai)
59
{
60
struct snd_soc_component *component = dai->component;
61
int ret;
62
63
ret = aiu_fifo_trigger(substream, cmd, dai);
64
if (ret)
65
return ret;
66
67
switch (cmd) {
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);
72
break;
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);
77
break;
78
default:
79
return -EINVAL;
80
}
81
82
return 0;
83
}
84
85
static int fifo_spdif_prepare(struct snd_pcm_substream *substream,
86
struct snd_soc_dai *dai)
87
{
88
struct snd_soc_component *component = dai->component;
89
int ret;
90
91
ret = aiu_fifo_prepare(substream, dai);
92
if (ret)
93
return ret;
94
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);
102
103
return 0;
104
}
105
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)
109
{
110
struct snd_soc_component *component = dai->component;
111
unsigned int val;
112
int ret;
113
114
ret = aiu_fifo_hw_params(substream, params, dai);
115
if (ret)
116
return ret;
117
118
val = AIU_MEM_IEC958_CONTROL_RD_DDR |
119
AIU_MEM_IEC958_CONTROL_MODE_LINEAR;
120
121
switch (params_physical_width(params)) {
122
case 16:
123
val |= AIU_MEM_IEC958_CONTROL_MODE_16BIT;
124
break;
125
case 32:
126
break;
127
default:
128
dev_err(dai->dev, "Unsupported physical width %u\n",
129
params_physical_width(params));
130
return -EINVAL;
131
}
132
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,
138
val);
139
140
/* Number bytes read by the FIFO between each IRQ */
141
snd_soc_component_write(component, AIU_IEC958_BPF,
142
params_period_bytes(params));
143
144
/*
145
* AUTO_DISABLE and SYNC_HEAD are enabled by default but
146
* this should be disabled in PCM (uncompressed) mode
147
*/
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);
153
154
return 0;
155
}
156
157
const struct snd_soc_dai_ops aiu_fifo_spdif_dai_ops = {
158
.pcm_new = aiu_fifo_pcm_new,
159
.probe = aiu_fifo_spdif_dai_probe,
160
.remove = aiu_fifo_dai_remove,
161
.trigger = fifo_spdif_trigger,
162
.prepare = fifo_spdif_prepare,
163
.hw_params = fifo_spdif_hw_params,
164
.startup = aiu_fifo_startup,
165
.shutdown = aiu_fifo_shutdown,
166
};
167
168
int aiu_fifo_spdif_dai_probe(struct snd_soc_dai *dai)
169
{
170
struct snd_soc_component *component = dai->component;
171
struct aiu *aiu = snd_soc_component_get_drvdata(component);
172
struct aiu_fifo *fifo;
173
int ret;
174
175
ret = aiu_fifo_dai_probe(dai);
176
if (ret)
177
return ret;
178
179
fifo = snd_soc_dai_dma_data_get_playback(dai);
180
181
fifo->pcm = &fifo_spdif_pcm;
182
fifo->mem_offset = AIU_MEM_IEC958_START;
183
fifo->fifo_block = 1;
184
fifo->pclk = aiu->spdif.clks[PCLK].clk;
185
fifo->irq = aiu->spdif.irq;
186
187
return 0;
188
}
189
190