Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/soc/mediatek/mt8365/mt8365-dai-pcm.c
26488 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* MediaTek 8365 ALSA SoC Audio DAI PCM Control
4
*
5
* Copyright (c) 2024 MediaTek Inc.
6
* Authors: Jia Zeng <[email protected]>
7
* Alexandre Mergnat <[email protected]>
8
*/
9
10
#include <linux/bitops.h>
11
#include <linux/regmap.h>
12
#include <sound/pcm_params.h>
13
#include "mt8365-afe-clk.h"
14
#include "mt8365-afe-common.h"
15
16
struct mt8365_pcm_intf_data {
17
bool slave_mode;
18
bool lrck_inv;
19
bool bck_inv;
20
unsigned int format;
21
};
22
23
/* DAI Drivers */
24
25
static void mt8365_dai_enable_pcm1(struct mtk_base_afe *afe)
26
{
27
regmap_update_bits(afe->regmap, PCM_INTF_CON1,
28
PCM_INTF_CON1_EN, PCM_INTF_CON1_EN);
29
}
30
31
static void mt8365_dai_disable_pcm1(struct mtk_base_afe *afe)
32
{
33
regmap_update_bits(afe->regmap, PCM_INTF_CON1,
34
PCM_INTF_CON1_EN, 0x0);
35
}
36
37
static int mt8365_dai_configure_pcm1(struct snd_pcm_substream *substream,
38
struct snd_soc_dai *dai)
39
{
40
struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
41
struct mt8365_afe_private *afe_priv = afe->platform_priv;
42
struct mt8365_pcm_intf_data *pcm_priv = afe_priv->dai_priv[MT8365_AFE_IO_PCM1];
43
bool slave_mode = pcm_priv->slave_mode;
44
bool lrck_inv = pcm_priv->lrck_inv;
45
bool bck_inv = pcm_priv->bck_inv;
46
unsigned int fmt = pcm_priv->format;
47
unsigned int bit_width = dai->symmetric_sample_bits;
48
unsigned int val = 0;
49
50
if (!slave_mode) {
51
val |= PCM_INTF_CON1_MASTER_MODE |
52
PCM_INTF_CON1_BYPASS_ASRC;
53
54
if (lrck_inv)
55
val |= PCM_INTF_CON1_SYNC_OUT_INV;
56
if (bck_inv)
57
val |= PCM_INTF_CON1_BCLK_OUT_INV;
58
} else {
59
val |= PCM_INTF_CON1_SLAVE_MODE;
60
61
if (lrck_inv)
62
val |= PCM_INTF_CON1_SYNC_IN_INV;
63
if (bck_inv)
64
val |= PCM_INTF_CON1_BCLK_IN_INV;
65
66
/* TODO: add asrc setting */
67
}
68
69
val |= FIELD_PREP(PCM_INTF_CON1_FORMAT_MASK, fmt);
70
71
if (fmt == MT8365_PCM_FORMAT_PCMA ||
72
fmt == MT8365_PCM_FORMAT_PCMB)
73
val |= PCM_INTF_CON1_SYNC_LEN(1);
74
else
75
val |= PCM_INTF_CON1_SYNC_LEN(bit_width);
76
77
switch (substream->runtime->rate) {
78
case 48000:
79
val |= PCM_INTF_CON1_FS_48K;
80
break;
81
case 32000:
82
val |= PCM_INTF_CON1_FS_32K;
83
break;
84
case 16000:
85
val |= PCM_INTF_CON1_FS_16K;
86
break;
87
case 8000:
88
val |= PCM_INTF_CON1_FS_8K;
89
break;
90
default:
91
return -EINVAL;
92
}
93
94
if (bit_width > 16)
95
val |= PCM_INTF_CON1_24BIT | PCM_INTF_CON1_64BCK;
96
else
97
val |= PCM_INTF_CON1_16BIT | PCM_INTF_CON1_32BCK;
98
99
val |= PCM_INTF_CON1_EXT_MODEM;
100
101
regmap_update_bits(afe->regmap, PCM_INTF_CON1,
102
PCM_INTF_CON1_CONFIG_MASK, val);
103
104
return 0;
105
}
106
107
static int mt8365_dai_pcm1_startup(struct snd_pcm_substream *substream,
108
struct snd_soc_dai *dai)
109
{
110
struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
111
112
if (snd_soc_dai_active(dai))
113
return 0;
114
115
mt8365_afe_enable_main_clk(afe);
116
117
return 0;
118
}
119
120
static void mt8365_dai_pcm1_shutdown(struct snd_pcm_substream *substream,
121
struct snd_soc_dai *dai)
122
{
123
struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
124
125
if (snd_soc_dai_active(dai))
126
return;
127
128
mt8365_dai_disable_pcm1(afe);
129
mt8365_afe_disable_main_clk(afe);
130
}
131
132
static int mt8365_dai_pcm1_prepare(struct snd_pcm_substream *substream,
133
struct snd_soc_dai *dai)
134
{
135
struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
136
int ret;
137
138
if ((snd_soc_dai_stream_active(dai, SNDRV_PCM_STREAM_PLAYBACK) +
139
snd_soc_dai_stream_active(dai, SNDRV_PCM_STREAM_CAPTURE)) > 1) {
140
dev_info(afe->dev, "%s '%s' active(%u-%u) already\n",
141
__func__, snd_pcm_stream_str(substream),
142
snd_soc_dai_stream_active(dai, SNDRV_PCM_STREAM_PLAYBACK),
143
snd_soc_dai_stream_active(dai, SNDRV_PCM_STREAM_CAPTURE));
144
return 0;
145
}
146
147
ret = mt8365_dai_configure_pcm1(substream, dai);
148
if (ret)
149
return ret;
150
151
mt8365_dai_enable_pcm1(afe);
152
153
return 0;
154
}
155
156
static int mt8365_dai_pcm1_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
157
{
158
struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai);
159
struct mt8365_afe_private *afe_priv = afe->platform_priv;
160
struct mt8365_pcm_intf_data *pcm_priv = afe_priv->dai_priv[MT8365_AFE_IO_PCM1];
161
162
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
163
case SND_SOC_DAIFMT_I2S:
164
pcm_priv->format = MT8365_PCM_FORMAT_I2S;
165
break;
166
default:
167
return -EINVAL;
168
}
169
170
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
171
case SND_SOC_DAIFMT_NB_NF:
172
pcm_priv->bck_inv = false;
173
pcm_priv->lrck_inv = false;
174
break;
175
case SND_SOC_DAIFMT_NB_IF:
176
pcm_priv->bck_inv = false;
177
pcm_priv->lrck_inv = true;
178
break;
179
case SND_SOC_DAIFMT_IB_NF:
180
pcm_priv->bck_inv = true;
181
pcm_priv->lrck_inv = false;
182
break;
183
case SND_SOC_DAIFMT_IB_IF:
184
pcm_priv->bck_inv = true;
185
pcm_priv->lrck_inv = true;
186
break;
187
default:
188
return -EINVAL;
189
}
190
191
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
192
case SND_SOC_DAIFMT_CBP_CFP:
193
pcm_priv->slave_mode = true;
194
break;
195
case SND_SOC_DAIFMT_CBC_CFC:
196
pcm_priv->slave_mode = false;
197
break;
198
default:
199
return -EINVAL;
200
}
201
202
return 0;
203
}
204
205
static const struct snd_soc_dai_ops mt8365_dai_pcm1_ops = {
206
.startup = mt8365_dai_pcm1_startup,
207
.shutdown = mt8365_dai_pcm1_shutdown,
208
.prepare = mt8365_dai_pcm1_prepare,
209
.set_fmt = mt8365_dai_pcm1_set_fmt,
210
};
211
212
static struct snd_soc_dai_driver mtk_dai_pcm_driver[] = {
213
{
214
.name = "PCM1",
215
.id = MT8365_AFE_IO_PCM1,
216
.playback = {
217
.stream_name = "PCM1 Playback",
218
.channels_min = 1,
219
.channels_max = 2,
220
.rates = SNDRV_PCM_RATE_8000 |
221
SNDRV_PCM_RATE_16000 |
222
SNDRV_PCM_RATE_32000 |
223
SNDRV_PCM_RATE_48000,
224
.formats = SNDRV_PCM_FMTBIT_S16_LE |
225
SNDRV_PCM_FMTBIT_S32_LE,
226
},
227
.capture = {
228
.stream_name = "PCM1 Capture",
229
.channels_min = 1,
230
.channels_max = 2,
231
.rates = SNDRV_PCM_RATE_8000 |
232
SNDRV_PCM_RATE_16000 |
233
SNDRV_PCM_RATE_32000 |
234
SNDRV_PCM_RATE_48000,
235
.formats = SNDRV_PCM_FMTBIT_S16_LE |
236
SNDRV_PCM_FMTBIT_S32_LE,
237
},
238
.ops = &mt8365_dai_pcm1_ops,
239
.symmetric_rate = 1,
240
.symmetric_sample_bits = 1,
241
}
242
};
243
244
/* DAI widget */
245
246
static const struct snd_soc_dapm_widget mtk_dai_pcm_widgets[] = {
247
SND_SOC_DAPM_OUTPUT("PCM1 Out"),
248
SND_SOC_DAPM_INPUT("PCM1 In"),
249
};
250
251
/* DAI route */
252
253
static const struct snd_soc_dapm_route mtk_dai_pcm_routes[] = {
254
{"PCM1 Playback", NULL, "O07"},
255
{"PCM1 Playback", NULL, "O08"},
256
{"PCM1 Out", NULL, "PCM1 Playback"},
257
258
{"I09", NULL, "PCM1 Capture"},
259
{"I22", NULL, "PCM1 Capture"},
260
{"PCM1 Capture", NULL, "PCM1 In"},
261
};
262
263
static int init_pcmif_priv_data(struct mtk_base_afe *afe)
264
{
265
struct mt8365_afe_private *afe_priv = afe->platform_priv;
266
struct mt8365_pcm_intf_data *pcmif_priv;
267
268
pcmif_priv = devm_kzalloc(afe->dev, sizeof(struct mt8365_pcm_intf_data),
269
GFP_KERNEL);
270
if (!pcmif_priv)
271
return -ENOMEM;
272
273
afe_priv->dai_priv[MT8365_AFE_IO_PCM1] = pcmif_priv;
274
return 0;
275
}
276
277
int mt8365_dai_pcm_register(struct mtk_base_afe *afe)
278
{
279
struct mtk_base_afe_dai *dai;
280
281
dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL);
282
if (!dai)
283
return -ENOMEM;
284
285
list_add(&dai->list, &afe->sub_dais);
286
dai->dai_drivers = mtk_dai_pcm_driver;
287
dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_pcm_driver);
288
dai->dapm_widgets = mtk_dai_pcm_widgets;
289
dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_pcm_widgets);
290
dai->dapm_routes = mtk_dai_pcm_routes;
291
dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_pcm_routes);
292
return init_pcmif_priv_data(afe);
293
}
294
295